Бытует мнение, что CSS сложный. Существует много костылей, магии. Легко выстрелить себе в колено. Меня это печалит, потому что я так не считаю. Немного подумав, что можно сделать, я собрал 5 привычек разработчиков, которые мне не нравятся, и показал, как их избежать.
Устанавливать отступы, а потом сбрасывать их
Часто встречаю, что люди устанавливают отступы (margin или padding) для всех элементов, а потом сбрасывают у первого или последнего элемента. Не понимаю зачем писать два правила, когда можно обойтись одним. Проще же сразу установить отступ для нужных элементов.
Используйте один из следующих вариантов: nth-child/nth-of-type селекторы, псевдо-класс :not(), или комбинатор следующего соседнего элемента, более известный как +, и ваш CSS будет более простым и кратким.
Не делайте так
.item {
margin-right: 1rem;
}
.item:last-child {
margin-right: 0;
}
Вы можете использовать
.item:not(:last-child) {
margin-right: 1rem;
}
/*или*/
.item:nth-child(n+2) {
margin-left: 1rem;
}
/*или*/
.item + .item {
margin-left: 1rem;
}
Добавлять display: block для элементов с position: absolute или position: fixed
А знаете ли вы, что вам не нужно добавлять display: block для элементов c position: absolute или position: fixed, потому что это происходит по умолчанию?
Кроме того, если вы будете использовать inline-* значения, то они будут изменены следующим образом: inline или inline-block изменятся на block, inline-flex -> flex, inline-grid -> grid, и inline-table -> table.
Поэтому просто пишите position: absolute или position: fixed, и добавляйте display, только тогда, когда вам нужны значения flex или grid.
Не делайте так
.button::before {
content: "";
display: block;
position: absolute;
}
/*или*/
.button::before {
content: "";
display: block;
position: fixed;
}
Вы можете использовать
.button::before {
content: "";
position: absolute;
}
/*или*/
.button::before {
content: "";
position: fixed;
}
Использовать transform: translate(-50%, -50%) для центрирования
Cуществует популярная задача, которая попила немало крови. Особенно до 2015 года, когда все ее решения приводили к каким-то проблемам. Я говорю о центрировании элемента с произвольной высотой по двум осям.
В частности одним из решений было использовать комбинацию абсолютного позиционирования и свойства transform. Данный прием приводил к размытию текста в Chromium браузерах.
Но после появления flexbox этот прием, по моему мнению, не актуален. Мало того, что проблема размытия текста еще не решена, так еще нужно использовать 5 свойств. Поэтому я хочу поделиться приемом, который сократит код до 2 свойств.
Мы можем использовать margin: auto внутри flex-контейнера, и браузер расположит элемент по центру. Просто 2 свойства и все.
Не делайте так
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
Вы можете использовать
.parent {
display: flex;
}
.child {
margin: auto;
}
Можно использовать justify-content и align-items для этой задачи, но я не люблю этот прием, потому что существуют проблемы, к которым он приводит. О них я расскажу в отдельной статье.
Использовать width: 100% для блочных элементов
Мы часто используем flexbox для создания многоколоночной сетки, которая постепенно преобразовывается в одну колонку.
И чтобы преобразовать сетку в одну колонку разработчики использую width: 100%. Я не понимаю, зачем они это делают. Ведь элементы сетки являются блочными элементами, которые делают это по умолчанию без дополнительных свойств.
Соответственно нам не нужно использовать width: 100%, а следует написать медиа-запрос так, чтобы flexbox использовался только для создания многоколоночной сетки.
Не делайте так
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
.parent {
display: flex;
flex-wrap: wrap;
}
.child {
width: 100%;
}
@media (min-width: 1024px) {
.child {
width: 25%;
}
}
Вы можете использовать
<div class="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
@media (min-width: 1024px) {
.parent {
display: flex;
flex-wrap: wrap;
}
.child {
width: 25%;
}
}
Если вы знаете, почему нужно добавлять width:100% и мой способ не решает проблему, то напишите об этом в комментариях. Возможно, я что-то не учел. Спасибо
Задавать display: block для flex-элементов
При использовании flexbox важно помнить, что при создании flex-контейнера (добавляем display: flex), все дочерние элементы (flex-элементы) становятся blockified.
Это означает, что у элементов устанавливается свойство display, и у него могут быть только блочные значения. Соответственно, если установить inline или inline-block, то оно изменится на block, inline-flex -> flex, inline-grid -> grid и inline-table -> table.
Поэтому не добавляйте display: block к flex-элементам. Браузер сделает это сам.
Не делайте так
.parent {
display: flex;
}
.child {
display: block;
}
Вы можете использовать
.parent {
display: flex;
}
Заключение
Надеюсь мне удалось показать, как можно избежать простых ошибок, и вы воспользуйтесь моими советами. Если нет, то это будет на вашей совести!
P.S: Если у вас есть вопросы по CSS/HTML, то, не стесняйтесь, пишите мне на мою почту. Она указана в моем профиле на Хабре.
mSnus
Позвольте вам возразить...
Не равноценно, потому что в первом варианте вы гарантированно сбросили правую границу у нужного элемента, а во втором — унаследовали, и что там будет, вы не знаете.
С display:block вы и сами упоминаете, что flex тоже может быть позиционирован абсолютно, поэтому указать block или flex однозначно стоит.
Очень часто элементы могут поменять display с block на flex или обратно при подключении .css с мобильной вёрсткой.
И, конечно, имеет смысл задать display: block для flex-элементов, потому что сейчас они flex из-за контейнера с flex, а на мобильном их контейнер стал block и… или проще — унаследуют откуда-то display: inline-table/inline-flex и во flex-контейнере превратятся не в block, а в table/flex. Поэтому надёжнее прописать это явно.
Зачем эта сомнительная экономия?
melnik909 Автор
Скажите, пожалуйста, что вы имеете ввиду под «унаследовать»? У меня в голове несколько вариантов, поэтому спрашиваю
mSnus
В любых вариантах, собственно, какая разница, откуда прилетит? Тут либо надеяться, что на всём проекте и везде будет хорошая строгая верстка, либо слегка подстраховаться по привычке от любых глупостей, кроме !important.
Вот, кстати, что я бы назвал ошибкой верстки #1..
melnik909 Автор
Чем больше вы пишите CSS, тем сложнее управлять этим. Сложность заключается в том, что на один элемент применяются много одинаковых свойств. Отсюда получается переопределение.
Если не вешать одинаковые свойства, то не будет переопределения. Тут возникает вопрос. Как не вешать одинаковые свойства? Тут и заключается мастерство человека, который пишет CSS.
P.S. Я юзаю !important вместе с custom properties для настроек компонентов, чтобы избежать переопределений. Я к тому, что все относительно.