diff --git a/ionic/components/app/test/profile/index.ts b/ionic/components/app/test/profile/index.ts
index 89c84b2803..8403a4c139 100644
--- a/ionic/components/app/test/profile/index.ts
+++ b/ionic/components/app/test/profile/index.ts
@@ -20,7 +20,7 @@ export class ParallaxEffect {
elementRef: ElementRef
) {
this.ele = elementRef.nativeElement;
- this.scroller = this.ele.querySelector('.scroll-content');
+ this.scroller = this.ele.querySelector('scroll-content');
this.scroller.addEventListener('scroll', (e) => {
//this.counter.innerHTML = e.target.scrollTop;
dom.raf(() => {
diff --git a/ionic/components/app/test/profile/main.html b/ionic/components/app/test/profile/main.html
index 182a771708..d72ffcf178 100644
--- a/ionic/components/app/test/profile/main.html
+++ b/ionic/components/app/test/profile/main.html
@@ -47,7 +47,7 @@
ion-content {
background: transparent !important;
}
-.scroll-content {
+scroll-content {
padding-top: 300px;
}
diff --git a/ionic/components/content/content.scss b/ionic/components/content/content.scss
index cec8ae1b55..e0664acf13 100644
--- a/ionic/components/content/content.scss
+++ b/ionic/components/content/content.scss
@@ -10,17 +10,17 @@ ion-content {
display: block;
flex: 1;
background-color: $content-background-color;
-
- .scroll-content {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- overflow-y: auto;
- overflow-x: hidden;
- -webkit-overflow-scrolling: touch;
- will-change: scroll-position;
- }
-
+}
+
+scroll-content {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ display: block;
+ overflow-y: scroll; // has to be scroll for momentum scrolling, not auto
+ overflow-x: hidden;
+ -webkit-overflow-scrolling: touch;
+ will-change: scroll-position;
}
diff --git a/ionic/components/content/content.ts b/ionic/components/content/content.ts
index 69c3000d31..2f65d20cc8 100644
--- a/ionic/components/content/content.ts
+++ b/ionic/components/content/content.ts
@@ -4,7 +4,7 @@ import {Ion} from '../ion';
import {IonicConfig} from '../../config/config';
import {IonicComponent} from '../../config/annotations';
import {ScrollTo} from '../../animations/scroll-to';
-import {Platform} from '../../platform/platform';
+import {hasFocusedTextInput} from '../../util/dom';
@Component({
@@ -14,11 +14,12 @@ import {Platform} from '../../platform/platform';
]
})
@View({
- template: '
'
+ template: ''
})
export class Content extends Ion {
constructor(elementRef: ElementRef, config: IonicConfig) {
super(elementRef, config);
+ this.scrollPadding = 0;
}
onIonInit() {
@@ -66,13 +67,13 @@ export class Content extends Ion {
let parentElement = scrollElement.parentElement;
return {
- height: parentElement.offsetHeight,
- top: parentElement.offsetTop,
- bottom: parentElement.offsetTop + parentElement.offsetHeight,
+ contentHeight: parentElement.offsetHeight,
+ contentTop: parentElement.offsetTop,
+ contentBottom: parentElement.offsetTop + parentElement.offsetHeight,
- width: parentElement.offsetWidth,
- left: parentElement.offsetLeft,
- right: parentElement.offsetLeft + parentElement.offsetWidth,
+ contentWidth: parentElement.offsetWidth,
+ contentLeft: parentElement.offsetLeft,
+ contentRight: parentElement.offsetLeft + parentElement.offsetWidth,
scrollHeight: scrollElement.scrollHeight,
scrollTop: scrollElement.scrollTop,
@@ -81,8 +82,31 @@ export class Content extends Ion {
scrollWidth: scrollElement.scrollWidth,
scrollLeft: scrollElement.scrollLeft,
scrollRight: scrollElement.scrollLeft + scrollElement.scrollWidth,
+ }
+ }
- keyboardTop: (Platform.height() * 0.6)
+ addKeyboardPadding(addPadding) {
+ if (addPadding > this.scrollPadding) {
+ this.scrollPadding = addPadding;
+ this.scrollElement.style.paddingBottom = addPadding + 'px';
+ }
+ }
+
+ pollFocus() {
+ if (hasFocusedTextInput()) {
+ this.isPollingFocus = true;
+
+ setTimeout(() => {
+ this.pollFocus();
+ }, 500);
+
+ } else {
+ this.isPollingFocus = false;
+
+ if (this.scrollPadding) {
+ this.scrollPadding = 0;
+ this.scrollElement.style.paddingBottom = '';
+ }
}
}
diff --git a/ionic/components/scroll/pull-to-refresh.scss b/ionic/components/scroll/pull-to-refresh.scss
index 485888130b..1ee2dcf1ff 100644
--- a/ionic/components/scroll/pull-to-refresh.scss
+++ b/ionic/components/scroll/pull-to-refresh.scss
@@ -74,7 +74,7 @@ ion-refresher {
}
}
}
-.scroll-content.overscroll {
+scroll-content.overscroll {
overflow: visible;
}
/*
diff --git a/ionic/components/scroll/scroll.scss b/ionic/components/scroll/scroll.scss
index 88eec07982..ca639122fe 100644
--- a/ionic/components/scroll/scroll.scss
+++ b/ionic/components/scroll/scroll.scss
@@ -1,14 +1,14 @@
ion-scroll {
position: relative;
display: block;
- &.scroll-x .scroll-content {
+ &.scroll-x scroll-content {
overflow-x: auto;
}
- &.scroll-y .scroll-content {
+ &.scroll-y scroll-content {
overflow-y: auto;
}
- .scroll-content {
+ scroll-content {
position: absolute;
top: 0;
right: 0;
diff --git a/ionic/components/scroll/scroll.ts b/ionic/components/scroll/scroll.ts
index 673177f223..ece72e1b8d 100644
--- a/ionic/components/scroll/scroll.ts
+++ b/ionic/components/scroll/scroll.ts
@@ -20,7 +20,7 @@ import {IonicComponent} from '../../config/annotations';
}
})
@View({
- template: '
'
+ template: ''
})
export class Scroll extends Ion {
constructor(elementRef: ElementRef, ionicConfig: IonicConfig) {
diff --git a/ionic/components/text-input/test/text-input.spec.ts b/ionic/components/text-input/test/text-input.spec.ts
index 0f8aa517fd..9df39f6f5c 100644
--- a/ionic/components/text-input/test/text-input.spec.ts
+++ b/ionic/components/text-input/test/text-input.spec.ts
@@ -2,8 +2,129 @@ import {TextInput} from 'ionic/ionic';
export function run() {
- it('should not scroll', () => {
- let input = new TextInput();
+ it('should scroll, top and bottom below safe area, no room to scroll', () => {
+
+ let inputOffsetTop = 350;
+ let inputOffsetHeight = 35;
+ let scrollViewDimensions = {
+ contentTop: 100,
+ contentHeight: 700,
+ scrollTop: 30,
+ scrollHeight: 700
+ };
+ let keyboardHeight = 400;
+
+ let scrollData = TextInput.getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions, keyboardHeight);
+
+ expect(scrollData.scrollAmount).toBe(-178.5);
+ expect(scrollData.scrollTo).toBe(208.5);
+ expect(scrollData.scrollPadding).toBe(523.5);
+ });
+
+ it('should scroll, top and bottom below safe area, room to scroll', () => {
+
+ let inputOffsetTop = 350;
+ let inputOffsetHeight = 35;
+ let scrollViewDimensions = {
+ contentTop: 100,
+ contentHeight: 700,
+ scrollTop: 30,
+ scrollHeight: 1000
+ };
+ let keyboardHeight = 400;
+
+ let scrollData = TextInput.getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions, keyboardHeight);
+
+ expect(scrollData.scrollAmount).toBe(-178.5);
+ expect(scrollData.scrollTo).toBe(208.5);
+ expect(scrollData.scrollPadding).toBe(0);
+ });
+
+ it('should scroll, top above safe', () => {
+ // Input top within safe area, bottom below safe area, room to scroll
+ let inputOffsetTop = 100;
+ let inputOffsetHeight = 33;
+ let scrollViewDimensions = {
+ contentTop: 100,
+ contentHeight: 700,
+ scrollTop: 250,
+ scrollHeight: 700
+ };
+ let keyboardHeight = 400;
+
+ let scrollData = TextInput.getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions, keyboardHeight);
+
+ expect(scrollData.scrollAmount).toBe(150);
+ expect(scrollData.scrollTo).toBe(100);
+ expect(scrollData.scrollPadding).toBe(0);
+ });
+
+ it('should scroll, top in safe, bottom below safe, below more than top in, not enough padding', () => {
+ // Input top within safe area, bottom below safe area, room to scroll
+ let inputOffsetTop = 100;
+ let inputOffsetHeight = 320;
+ let scrollViewDimensions = {
+ contentTop: 100,
+ contentHeight: 700,
+ scrollTop: 20,
+ scrollHeight: 700
+ };
+ let keyboardHeight = 400;
+
+ let scrollData = TextInput.getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions, keyboardHeight);
+
+ expect(scrollData.scrollAmount).toBe(-80);
+ expect(scrollData.scrollTo).toBe(100);
+ expect(scrollData.scrollPadding).toBe(523.5);
+ });
+
+ it('should scroll, top in safe, bottom below safe, below more than top in, enough padding', () => {
+ // Input top within safe area, bottom below safe area, room to scroll
+ let inputOffsetTop = 20;
+ let inputOffsetHeight = 330;
+ let scrollViewDimensions = {
+ contentTop: 100,
+ scrollTop: 0,
+ };
+ let keyboardHeight = 400;
+
+ let scrollData = TextInput.getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions, keyboardHeight);
+
+ expect(scrollData.scrollAmount).toBe(-20);
+ expect(scrollData.scrollTo).toBe(20);
+ expect(scrollData.scrollPadding).toBe(0);
+ });
+
+ it('should scroll, top in safe, bottom below safe, below less than top in, enough padding', () => {
+ // Input top within safe area, bottom below safe area, room to scroll
+ let inputOffsetTop = 250;
+ let inputOffsetHeight = 80; // goes 30px below safe area
+ let scrollViewDimensions = {
+ contentTop: 100,
+ scrollTop: 0,
+ };
+ let keyboardHeight = 400;
+
+ let scrollData = TextInput.getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions, keyboardHeight);
+
+ expect(scrollData.scrollAmount).toBe(-153.5);
+ expect(scrollData.scrollTo).toBe(153.5);
+ expect(scrollData.scrollPadding).toBe(0);
+ });
+
+ it('should not scroll, top in safe, bottom in safe', () => {
+ // Input top within safe area, bottom within safe area
+ let inputOffsetTop = 100;
+ let inputOffsetHeight = 50;
+ let scrollViewDimensions = {
+ contentTop: 100,
+ scrollTop: 0,
+ keyboardTop: 400
+ };
+ let keyboardHeight = 400;
+
+ let scrollData = TextInput.getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions, keyboardHeight);
+ expect(scrollData.noScroll).toBe(true);
});
}
diff --git a/ionic/components/text-input/text-input.ts b/ionic/components/text-input/text-input.ts
index 8dab08ba54..eba0909075 100644
--- a/ionic/components/text-input/text-input.ts
+++ b/ionic/components/text-input/text-input.ts
@@ -9,6 +9,7 @@ import {IonicApp} from '../app/app';
import {Content} from '../content/content';
import {ClickBlock} from '../../util/click-block';
import * as dom from '../../util/dom';
+import {Platform} from '../../platform/platform';
@@ -161,16 +162,21 @@ export class TextInput extends Ion {
// find out if text input should be manually scrolled into view
let ele = this.elementRef.nativeElement;
- let scrollData = this.getScollData(ele.offsetTop, ele.offsetHeight, scrollView.getDimensions());
+ let keyboardHeight = this.config.setting('keyboardHeight');
+
+ let scrollData = TextInput.getScollData(ele.offsetTop, ele.offsetHeight, scrollView.getDimensions(), keyboardHeight);
if (scrollData.noScroll) {
// the text input is in a safe position that doesn't require
// it to be scrolled into view, just set focus now
return this.setFocus();
}
+ // add padding to the bottom of the scroll view (if needed)
+ scrollView.addKeyboardPadding(scrollData.scrollPadding);
+
// manually scroll the text input to the top
// do not allow any clicks while it's scrolling
- ClickBlock(true, SCROLL_INTO_VIEW_DURATION + 200);
+ ClickBlock(true, SCROLL_INTO_VIEW_DURATION + 100);
// temporarily move the focus to the focus holder so the browser
// doesn't freak out while it's trying to get the input in place
@@ -178,7 +184,7 @@ export class TextInput extends Ion {
this.tempFocusMove();
// scroll the input into place
- scrollView.scrollTo(0, scrollData.scrollTo, SCROLL_INTO_VIEW_DURATION, 8).then(() => {
+ scrollView.scrollTo(0, scrollData.scrollTo, SCROLL_INTO_VIEW_DURATION, 6).then(() => {
// the scroll view is in the correct position now
// give the native text input focus
this.setFocus();
@@ -194,21 +200,22 @@ export class TextInput extends Ion {
}
- getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions) {
+ static getScollData(inputOffsetTop, inputOffsetHeight, scrollViewDimensions, keyboardHeight) {
// compute input's Y values relative to the body
- let inputTop = (inputOffsetTop + scrollViewDimensions.top - scrollViewDimensions.scrollTop);
+ let inputTop = (inputOffsetTop + scrollViewDimensions.contentTop - scrollViewDimensions.scrollTop);
let inputBottom = (inputTop + inputOffsetHeight);
// compute the safe area which is the viewable content area when the soft keyboard is up
- let safeAreaTop = (scrollViewDimensions.top - 1);
- let safeAreaBottom = scrollViewDimensions.keyboardTop;
- let safeAreaHeight = (safeAreaBottom - safeAreaTop);
+ let safeAreaTop = scrollViewDimensions.contentTop;
+ let safeAreaHeight = Platform.height() - keyboardHeight - safeAreaTop;
+ safeAreaHeight /= 2;
+ let safeAreaBottom = safeAreaTop + safeAreaHeight;
let inputTopWithinSafeArea = (inputTop >= safeAreaTop && inputTop <= safeAreaBottom);
+ let inputTopAboveSafeArea = (inputTop < safeAreaTop);
+ let inputTopBelowSafeArea = (inputTop > safeAreaBottom);
let inputBottomWithinSafeArea = (inputBottom >= safeAreaTop && inputBottom <= safeAreaBottom);
let inputBottomBelowSafeArea = (inputBottom > safeAreaBottom);
- let inputFitsWithinSafeArea = (inputOffsetHeight <= safeAreaHeight);
- let distanceInputBottomBelowSafeArea = (safeAreaBottom - inputBottom);
/*
Text Input Scroll To Scenarios
@@ -231,34 +238,74 @@ export class TextInput extends Ion {
// looks like we'll have to do some auto-scrolling
let scrollData = {
scrollAmount: 0,
- scrollTo: inputOffsetTop,
+ scrollTo: 0,
scrollPadding: 0,
};
- if (inputTopWithinSafeArea && inputBottomBelowSafeArea) {
- // Input top within safe area, bottom below safe area
- let distanceInputTopIntoSafeArea = (safeAreaTop - inputTop);
- let distanceInputBottomBelowSafeArea = (inputBottom - safeAreaBottom);
+ if (inputTopBelowSafeArea || inputBottomBelowSafeArea) {
+ // Input top and bottom below safe area
+ // auto scroll the input up so at least the top of it shows
- if (distanceInputBottomBelowSafeArea < distanceInputTopIntoSafeArea) {
- // the input's top is farther into the safe area then the bottom is out of it
- // this means we can scroll it up a little bit and the top will still be
- // within the safe area
- scrollData.scrollAmount = distanceInputTopIntoSafeArea * -1;
+ if (safeAreaHeight > inputOffsetHeight) {
+ // safe area height is taller than the input height, so we
+ // can bring it up the input just enough to show the input bottom
+ scrollData.scrollAmount = (safeAreaBottom - inputBottom);
} else {
- // the input's top is less below the safe area top than the
- // input's bottom is below the safe area bottom. So scroll the input
- // to be at the top of the safe area, knowing that the bottom will go below
- scrollData.scrollAmount = distanceInputTopIntoSafeArea * -1;
+ // safe area height is smaller than the input height, so we can
+ // only scroll it up so the input top is at the top of the safe area
+ // however the input bottom will be below the safe area
+ scrollData.scrollAmount = (safeAreaTop - inputTop);
}
+
+ } else if (inputTopAboveSafeArea) {
+ // Input top above safe area
+ // auto scroll the input down so at least the top of it shows
+ scrollData.scrollAmount = (safeAreaTop - inputTop);
+
}
- scrollData.scrollTo = (inputOffsetTop + scrollData.scrollAmount);
+ // figure out where it should scroll to for the best position to the input
+ scrollData.scrollTo = (scrollViewDimensions.scrollTop - scrollData.scrollAmount);
+ if (scrollData.scrollAmount < 0) {
+ // when auto-scrolling up, there also needs to be enough
+ // content padding at the bottom of the scroll view
+ // manually add it if there isn't enough scrollable area
+
+ // figure out how many scrollable area is left to scroll up
+ let availablePadding = (scrollViewDimensions.scrollHeight - scrollViewDimensions.scrollTop) - scrollViewDimensions.contentHeight;
+
+ let paddingSpace = availablePadding + scrollData.scrollAmount;
+ if (paddingSpace < 0) {
+ // there's not enough scrollable area at the bottom, so manually add more
+ scrollData.scrollPadding = (scrollViewDimensions.contentHeight - safeAreaHeight);
+ }
+ }
+
+ // if (!window.safeAreaEle) {
+ // window.safeAreaEle = document.createElement('div');
+ // window.safeAreaEle.style.position = 'absolute';
+ // window.safeAreaEle.style.background = 'rgba(0, 128, 0, 0.3)';
+ // window.safeAreaEle.style.padding = '10px';
+ // window.safeAreaEle.style.textShadow = '2px 2px white';
+ // window.safeAreaEle.style.left = '0px';
+ // window.safeAreaEle.style.right = '0px';
+ // window.safeAreaEle.style.pointerEvents = 'none';
+ // document.body.appendChild(window.safeAreaEle);
+ // }
+ // window.safeAreaEle.style.top = safeAreaTop + 'px';
+ // window.safeAreaEle.style.height = safeAreaHeight + 'px';
+ // window.safeAreaEle.innerHTML = `
+ // scrollTo: ${scrollData.scrollTo}
+ // scrollAmount: ${scrollData.scrollAmount}
+ // scrollPadding: ${scrollData.scrollPadding}
+ // scrollHeight: ${scrollViewDimensions.scrollHeight}
+ // scrollTop: ${scrollViewDimensions.scrollTop}
+ // contentHeight: ${scrollViewDimensions.contentHeight}
+ // `;
- // fallback for whatever reason
return scrollData;
}
@@ -268,12 +315,21 @@ export class TextInput extends Ion {
setFocus() {
this.zone.run(() => {
+ // set focus on the input element
this.input && this.input.setFocus();
+
+ // ensure the body hasn't scrolled down
+ document.body.scrollTop = 0;
+
IonInput.setAsLastInput(this);
});
if (this.scrollAssist && this.scrollView) {
setTimeout(() => {
+ if (!this.scrollView.isPollingFocus) {
+ this.scrollView.pollFocus();
+ }
+
this.deregListeners();
this.deregScroll = this.scrollView.addScrollEventListener(this.scrollMove);
}, 100);
@@ -306,4 +362,4 @@ export class TextInput extends Ion {
}
-const SCROLL_INTO_VIEW_DURATION = 500;
+const SCROLL_INTO_VIEW_DURATION = 400;
diff --git a/ionic/config/modes.ts b/ionic/config/modes.ts
index b2401b46c7..de45fd08b9 100644
--- a/ionic/config/modes.ts
+++ b/ionic/config/modes.ts
@@ -16,9 +16,6 @@ IonicConfig.modeConfig('ios', {
iconForward: 'ion-ios-arrow-forward',
iconMode: 'ios',
- keyboardScrollAssist: true,
- tapPolyfill: false,
-
navTitleAlign: 'center',
tabBarPlacement: 'bottom',
viewTransition: 'ios',
@@ -40,9 +37,6 @@ IonicConfig.modeConfig('md', {
iconForward: '',
iconMode: 'md',
- keyboardScrollAssist: true,
- tapPolyfill: false,
-
navTitleAlign: 'left',
tabBarPlacement: 'top',
viewTransition: 'md',
diff --git a/ionic/platform/registry.ts b/ionic/platform/registry.ts
index e67fdc2ca7..f6efc7f3d1 100644
--- a/ionic/platform/registry.ts
+++ b/ionic/platform/registry.ts
@@ -5,6 +5,7 @@ Platform.register({
name: 'core',
settings: {
mode: 'ios',
+ keyboardHeight: 290,
}
});
Platform.setDefault('core');
@@ -20,7 +21,6 @@ Platform.register({
isMatch(p) {
let smallest = Math.min(p.width(), p.height());
let largest = Math.max(p.width(), p.height());
- // http://www.mydevice.io/devices/
return (smallest > 390 && smallest < 520) &&
(largest > 620 && largest < 800);
}
@@ -32,7 +32,6 @@ Platform.register({
isMatch(p) {
let smallest = Math.min(p.width(), p.height());
let largest = Math.max(p.width(), p.height());
- // http://www.mydevice.io/devices/
return (smallest > 460 && smallest < 820) &&
(largest > 780 && largest < 1400);
}
@@ -48,10 +47,11 @@ Platform.register({
],
settings: {
mode: 'md',
+ keyboardHeight: 290,
+ keyboardScrollAssist: true,
},
isMatch(p) {
- // "silk" is kindle fire
- return p.isPlatform('android', 'android| silk');
+ return p.isPlatform('android', 'android|silk');
},
versionParser(p) {
return p.matchUserAgentVersion(/Android (\d+).(\d+)?/);
@@ -70,10 +70,12 @@ Platform.register({
settings: {
mode: 'ios',
tapPolyfill: function() {
- // this ensures it's actually a physical iOS device
- // and not just an a spoofed user-agent string
return /iphone|ipad|ipod/i.test(Platform.navigatorPlatform());
},
+ keyboardScrollAssist: function() {
+ return /iphone|ipad|ipod/i.test(Platform.navigatorPlatform());
+ },
+ keyboardHeight: 290,
},
isMatch(p) {
return p.isPlatform('ios', 'iphone|ipad|ipod');
@@ -87,6 +89,9 @@ Platform.register({
Platform.register({
name: 'ipad',
superset: 'tablet',
+ settings: {
+ keyboardHeight: 500,
+ },
isMatch(p) {
return p.isPlatform('ipad');
}
diff --git a/ionic/util/dom.ts b/ionic/util/dom.ts
index 149944664e..57448005a5 100644
--- a/ionic/util/dom.ts
+++ b/ionic/util/dom.ts
@@ -179,3 +179,18 @@ export function hasPointerMoved(threshold, startCoord, endCoord) {
export function hasFocus(ele) {
return !!(ele && (document.activeElement === ele.nativeElement || document.activeElement === ele));
}
+
+export function isTextInput(ele) {
+ return !!ele &&
+ (ele.tagName == 'TEXTAREA' ||
+ ele.contentEditable === 'true' ||
+ (ele.tagName == 'INPUT' && !(/^(radio|checkbox|range|file|submit|reset|color|image|button)$/i).test(ele.type)));
+}
+
+export function hasFocusedTextInput() {
+ let ele = document.activeElement;
+ if (isTextInput(ele)) {
+ return (ele.parentElement.querySelector(':focus') === ele);
+ }
+ return false;
+}
diff --git a/ionic/util/util.scss b/ionic/util/util.scss
index 4059db92dc..9d86775a70 100755
--- a/ionic/util/util.scss
+++ b/ionic/util/util.scss
@@ -31,9 +31,10 @@
$content-padding: 10px !default;
-[padding], .padding,
-.padding > .scroll-content,
-[padding] > .scroll-content {
+.padding,
+[padding],
+.padding > scroll-content,
+[padding] > scroll-content {
padding: $content-padding;
}