Статьи

Центрирование с Sass

Центрирование в CSS хорошо известно как утомительное занятие. Это своего рода кляп из языка, приводящий к таким шуткам, как «нам удалось отправить людей на Луну, но мы не можем выровнять по вертикали в CSS».

Хотя CSS действительно немного сложен при работе с центрированием, особенно с вертикальным, я чувствую, что эти шутки немного несправедливы. На самом деле, существует множество способов центрировать контент в CSS, вы просто должны знать, как это сделать.

Эта статья не предназначена для объяснения того, как работают эти методы, но как мы можем обернуть их в миксин Sass для удобного и простого использования. Так что, если вы чувствуете себя немного неловко из-за центрирования CSS, могу я порекомендовать вам прочитать несколько ресурсов:

Все хорошо? Давайте начнем тогда.

О чем это все?

Во-первых, мы сосредоточимся на центрировании элемента в его родительском элементе, так как это наиболее распространенный вариант использования абсолютного центрирования (модалы, содержимое в разделе и т. Д.). Когда вы спрашиваете кого-то о CSS-центрировании, обычный ответ, который вы получаете в ответ: вы знаете размеры элемента? Причина этого вопроса в том, что если вы их не знаете, лучшее решение — это использовать CSS-преобразования. Он немного снижает поддержку браузера, но он очень гибкий. Если вы не можете использовать CSS-преобразования или знаете ширину и высоту элемента, тогда легко полагаться на отрицательные поля.

Таким образом, наш миксин собирается сделать это в основном: расположить верхний левый угол элемента абсолютно посередине контейнера, а затем сместить, если половина его ширины и половина его высоты либо с CSS-преобразованиями, либо с отрицательными полями, в зависимости от того, стоит ли Размеры передаются в миксин. Без измерений: идите за трансформациями; Размеры: используйте поля.

Вы бы тогда использовали это так:

/** * Enable position context for the child */ .parent { position: relative; } /** * Absolutely center the element in its parent * No dimensions are passed to the mixin, so it relies on CSS transforms */ .child-with-unknown-dimensions { @include center; } /** * Absolutely center the element in its parent * Width is passed to the mixin, so we rely on a negative margin for the * horizontal axis and CSS transforms for the vertical axis */ .child-with-known-width { @include center(400px); } /** * Absolutely center the element in its parent * Height is passed to the mixin, so we rely on a negative margin for the * vertical axis and CSS transforms for the horizontal axis */ .child-with-known-height { @include center($height: 400px); } /** * Absolutely center the element in its parent * Width is passed to the mixin, so we rely on a negative margins for both * horizontal axis and vertical axis */ .child-with-known-dimensions { @include center(400px, 400px); } 

После компиляции он должен вывести это:

 §.parent { position: relative; } .child-with-unknown-dimensions { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .child-with-known-width { position: absolute; top: 50%; left: 50%; margin-left: -200px; width: 400px; transform: translateY(-50%); } .child-with-known-height { position: absolute; top: 50%; left: 50%; transform: translateX(-50%); margin-top: -200px; height: 400px; } .child-with-known-dimensions { position: absolute; top: 50%; left: 50%; margin-left: -200px; width: 400px; margin-top: -200px; height: 400px; } 

Хорошо, это выглядит немного многословно, но имейте в виду, что этот вывод для демонстрационных целей. Маловероятно, что вы используете их все в данной ситуации.

Строим миксин

Хорошо, давайте копать. Из предыдущих фрагментов кода мы уже знаем сигнатуру нашего миксина: она имеет два необязательных параметра: $width и $height .

  

Двигаемся дальше. При любых обстоятельствах миксин должен сделать элемент абсолютно позиционированным, поэтому мы можем начать с этого.

 @mixin center($width: null, $height: null) { position: absolute; top: 50%; left: 50%; // Moar magic here... } 

Мы должны быть умными с нашим кодом. Давайте на секунду остановимся и проанализируем различные варианты:

ширина Высота Решение
Неопределенный Неопределенный translate
определенный определенный margin
определенный Неопределенный margin-left + translateY
Неопределенный определенный translateX + margin-top

Пойдем с этим.

 @mixin center($width: null, $height: null) { position: absolute; top: 50%; left: 50%; @if not $width and not $height { // Go with `translate` } @else if $width and $height { // Go width `margin` } @else if not $height { // Go with `margin-left` and `translateY` } @else { // Go with `margin-top` and `translateX` } } 

Теперь, когда мы создали скелет для нашего миксина, нам осталось только заполнить пробелы фактическими объявлениями CSS.

 @mixin center($width: null, $height: null) { position: absolute; top: 50%; left: 50%; @if not $width and not $height { transform: translate(-50%, -50%); } @else if $width and $height { width: $width; height: $height; margin: -($width / 2) #{0 0} -($height / 2); } @else if not $height { width: $width; margin-left: -($width / 2); transform: translateY(-50%); } @else { height: $height; margin-top: -($height / 2); transform: translateX(-50%); } } 

Примечание: трюк #{0 0} является грязным хаком, чтобы предотвратить слегка агрессивную минимизацию от Sass, которая приведет к margin: mt 0 ml вместо margin: mt 0 0 ml .

Все идет нормально.

Идти дальше

Есть несколько вещей, которые мы могли бы сделать, чтобы продвинуть наш миксин дальше, например, @supports правило @supports в @supports чтобы проверить поддержку преобразований CSS или предположить, что есть (или разрешить) Modernizr и выходные условия, в зависимости от того, являются ли преобразования CSS поддерживается. Мы также могли бы сделать более агрессивную проверку аргументов, чтобы убедиться, что они являются допустимыми значениями width и height .

Хотя вы должны спросить себя, хорошо ли вам заходить так далеко. Миксин, как есть, уже имеет цикломатическую сложность 6, что немало для помощника Sass. Это все еще хорошо, но добавление большего количества кода, вероятно, означает дальнейшее увеличение сложности цикла.

Что насчет Flexbox?

Я уверен, что некоторые из вас, ребята, прыгают на вашем месте, думая о том, как мы можем использовать Flexbox для центрирования элемента в его родительском элементе. Действительно, это возможно, и это оказывается самым простым решением из всех, если вы можете себе это позволить.

Основное различие между решением, которое мы только что установили, и решением Flexbox в том, что последнее построено поверх родительского элемента, в то время как первое в основном фокусируется на дочернем элементе (при условии, что любой из его предков имеет position отличное от static ).

Чтобы элемент был центрирован по дочернему элементу (ren), вам нужно всего лишь напечатать триплет свойств. Вы можете сделать миксин, заполнитель, класс или все, что вам нравится для этого.

 @mixin center-children { display: flex; justify-content: center; align-items: center; } 

Если вы добавите соответствующие префиксы поставщиков (через mixin или Autoprefixer), это решение должно просто работать во многих браузерах .

 .parent { @include center-children; } 

Уступая, как вы наверняка догадываетесь

 .parent { display: flex; justify-content: center; align-items: center; } 

Последние мысли

Мы хотели, чтобы короткий миксин легко центрировал элемент внутри его родителя; этот делает работу, и он делает это хорошо. Он не только достаточно умен, чтобы работать независимо от того, имеет ли элемент определенные размеры, но также предоставляет дружественный и очевидный API, который чрезвычайно важен.

Глядя на код, любой сразу понимает, что @include center линия @include center является включением помощника, который выполняет некоторую логику, чтобы сделать элемент центрированным внутри своего родителя. Однако помните, что последний (или любой родительский элемент в дереве DOM) должен иметь положение, отличное от static чтобы это работало! 😉

Вы можете поиграть с кодом на SassMeister: http://sassmeister.com/gist/550809f5aa00b73d932c .