Pull to refresh

Comments 42

UFO just landed and posted this here
Можно и так. )
Или вот еще вариант:
.news__list-item + .news__list-item {
    margin-top: 18px;
}
В этом случае у вас растет специфичность (specificity), что ухудшает парсинг CSS кода при создании CSSOM.

.news__list-item:not(:first-child) в этом случае лучше чем .news__list-item + .news__list-item
Согласен. Я просто привел еще один вариант селектора.
специфичность обоих записей одинаковая
* + .news__list-item {margin-top: 18px;}

Так короче, и специфичность меньше
И проблем с чтением этой конструкции больше, особенно если понадобится удлинить эту цепочку.
Аргументируйте, пожалуйста.
На стековерфлоу. Если коротко — это один из самых медленных селекторов из-за особенностей браузеров разбора селекторов.

Вдобавок, может простреливать в очень неожиданные места.
Во-первых, приводить в пример статьи 2009-го года, где рассматривается производительность IE7,8 — как минимум не очень корректно. В реальности хоть сколько-нибудь заметные проблемы с производительностью могут наблюдаться, наверное, в случае каскада, когда универсальный селектор стоит справа, например ".class * " (помним, что браузеры разбирают селекторы справа налево, даже по вашей ссылке это написано), и стили для данного селектора вызывают reflow страницы.

Вот, например, есть статья немного посвежее (2012 год), показывающая, что разницы между одним универсальным селектором, и полным отсутствием селекторов — практически нет.

Вот статья 2014 года, показывающая, что на построение DOM и layout'а тратится значительно больше времени, чем на разбор селекторов.

Я это всё к чему — браузеры делают умные люди, и в наши дни они (браузеры) умеют оптимизировать отображение страничек намного лучше, чем во времена того же IE8. Если специально не стрелять себе в ногу, то сложность селекторов — это не первое, о чем стоит задумываться.
Звездочка говорит браузеру, что он должен еще разок пробежаться по всем элементам в DOM. Это всегда зло.
Ну, вообще говоря, это не совсем так. CSS-селекторы разбираются браузером справа налево, поэтому в случае с "* + X" браузер сначала найдет все элементы "X", а затем, увидев селектор соседнего элемента "+" — будет проверять только соседние элементы DOM'a (По моему скромному мнению, конечно. Я не разработчик браузеров, и не знаю как на самом деле всё работает).
Вот именно потому что вы не знаете как на самом деле и не знаете как будет завтра, хак с "* + X" использовать не стоит, и лучше опираться на стандарт, а не конкретную реализацию браузера
От чтения HTML с такими классами вытекают глаза.
Дело привычки. У меня уже не вытекают. :)
Наверное поэтому frontender.info/writing-efficient-css-selectors
Думаю в данном случае специфичность это хорошо, поскольку позволяет задавать разные отступы между разными элементами.
В вашем комментарии — да, но в комментарии MiXei4, на который я отвечал, конструкция
X:not(:first-child)

делает ровно то же, что и предложенная мной
* + X
Может оно и короче и делает тоже самое, но имеет проблемы с методологией подхода (в рамках БЭМ, раз тут БЭМ), читаемостью и оптимизированностью (так как любое * заставит просмотреть все элементы), в то время как
.news__list-item:not(:first-child)

будет работать только с уже выбранным массивом .news__list-item
Да и визуально сразу понятно что речь о .news__list-item в рамках которого любой элемент кроме :first-child
> так как любое * заставит просмотреть все элементы

Поскольку селекторы разбираются браузером справа налево, сначала браузер все равно выберет массив `.news__list-item` (самый правый элемент селектора). Так что на производительности это не отразится.

`*` — зло, когда он стоит справа в селекторе.
Ждал именно этого замечания. Да, сейчас браузер разбирает справа налево, но в случае с "* + X" нет гарантии, что браузер не преобразует этот селектор перед разбором в «X + *» для каких-то своих оптимизаций
Так же как нет гарантий, что следующее поколение движков не начнет разбирать селекторы слева направо

Тоесть использование "* + X" это хак, который может перестать работать, поэтому я и написал, что есть проблема в том числе и с оптимизированостью, потому что условно браузер должен просмотреть все элементы, но так как мы знаем, что браузер разбирает справо налево, то мы абузим «недокументированную» фичу, если продолжаем так делать
Честно говоря, впервые слышу, что браузер разбирает селекторы справа налево и меня это сильно удивляет. На практике часто использую такую технику для обнуления отступа последнего блока внутри компонента:
.box {

&__item-1 { margin-bottom: 30px }
&__item-2 { margin-bottom: 40px }
&__item-3 { margin-bottom: 25px }

> *:last-child {
margin-bottom: 0;
}
}

Выходит, в этом случае, браузер сначала найдёт все last-child теги на странице, а затем уже будет проверять какой из них находится внутри .box? Разве это имеет смысл?
Сначала найдёт все элементы, потом из них выберет те, которые внутри .box, потом от них возьмет :last-child
Как будет на самом деле — неизвестно, движок css современных браузеров загадка, до тех пор, пока кто нибудь не возьмется провести актуальное исследование

Одно ясно точно, если используется .box > *:last-child, и хочется привести к более БЭМ подходу, то есть несколько вариантов, например использование модификаторов:
<div class="box">
  <div class="box__item box__item_1">item1</div>
  <div class="box__item box__item_2">item2</div>
  <div class="box__item box__item_3">item3</div>
  <div class="box__item box__item_1">item4</div>
</div>


.box {
&__item_1 { margin-bottom: 30px }
&__item_2 { margin-bottom: 40px }
&__item_3 { margin-bottom: 25px }
&__item:last-child { margin-bottom: 0; }
}
справа налево, сначала найдет все ластчайлды данного класса.
э
В свое время пока не прочел книгу
CSS. Каскадные таблицы стилей. Эрика Мейера, часто мучился при верстке. Из тех книг что читал нигде не было указано что входит в высоту и ширину блока.
Думаю любой верстальщик, должен это знать, для себя ничего нового, разве, как напоминание, за что в принципе тоже можно сказать спасибо!
Про простую расстановку магических цифр, пожалуй что, каждый верстальщик и знает. А вот вдумчивый подход очень важен, у меня, например, он с опытом пришел, далеко не сразу, а если вот так хорошо объясняют — так это же замечательно.
UFO just landed and posted this here
Понравился подход с обязательностью/опциональностью блоков для установки отступов. Вроде мысль на поверхности, но как схема работы в голову раньше не приходила. Пригодится, спасибо.
Спасибо за хорошо написанную статью. Стоит так же отметить, что схлопывания еще часто называют margin collapse.
Наглядное и простое изложение, спасибо! С переводом терминоголоией margin и padding не везло раньше, было много путаницы.

+100500:
В боксовой модели (box model) поля — это расстояние между контентом (content) и границей блока (border). А отступы это расстояние между границей блока и границей соседнего или родительского элемента.
UFO just landed and posted this here
«Сложение» — тоже недвусмысленный термин, его можно неправильно понять, по крайней мере в русском языке.
Может быть, лучше «поглощение» полей?
С точки зрения корректности перевода вы правы. Но термин «отбивка» слишком типографский, я ни разу не слышал чтобы его употребляли верстальщики. В основном говорят «поля», «отступы», иногда «внешние поля».
Термин «сложение полей» не подходит, поскольку поля как раз не складываются, а берется максимальное значение. Тогда уж «наложение полей».
ИМХО, следует упомянуть еще и про такую полезнейшую вещь, как box-sizing, которая многих выручала при выходе элементов с width: 100% за пределы родительского элемента с padding-ом.
Извините, у меня крайняя степень слепоты… А за статью спасибо, толково и подробно :)
Спасибо за статью, мне б это руководство, когда учился верстать)
UFO just landed and posted this here
Дополню, уточню.

1. Рекомендую явно указывать вертикальные margin для каждого элемента, который в них нуждается, полагаться на влияние margin от соседнего элемента опасно, особенно при работе с пользовательским контентом.

Я для этого использую миксин:

@mixin ritm($valueTop, $valueBottom:$valueTop) {

@if $valueTop != 0 {
@include not(':first-child') {
margin-top: $valueTop;
}
}

@if $valueBottom != 0 {
@include not(':last-child') {
margin-bottom: $valueBottom;
}
}
}

2. Не стоит обеспечивать отступ между соседними блоками за счёт отступов дочерних элементов.

3. А отступы это расстояние между границей блока и границей соседнего или родительского элемента.
Верно, но тут есть тонкий момент. Стоит сделать оговорку, что margin является неотъемлемой частью блока, хоть и воспринимается как нечто попутное. Вопрос в том, что размеры блока, а конкретно его ширина, не всегда одно и тоже, что значение свойства width. Width — это ширина части бокса от border до border, либо размер контентной области в зависимости от боксовой модели, но размеры блока остаются неизменные, это стоит понимать.

Each box has four edges: the margin edge, border edge, padding edge, and content edge.
developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model

В ней у каждого бокса есть 4 области: margin (внешние отступы), border (рамка), padding (внутренние поля), и content (контент или содержимое).
developer.mozilla.org/ru/docs/Web/CSS/box_model

Each box has a content area (e.g., text, an image, etc.) and optional surrounding padding, border, and margin areas;
www.w3.org/TR/CSS2/box.html#box-dimensions

4. Таким образом, если граница и фон элемента не заданы, то нет разницы, использовать свойство padding или margin для задания отступов, но при условии, что ширина (width) и высота (height) элемента не заданы и не изменен алгоритм расчета размеров контента с помощью свойства box-sizing.
Для полноты картины, есть случаи, когда одинаковые значения margin и padding, даже при выше описанных условиях, производят различный результат, например margin: auto; ≠ padding: auto; codepen.io/matovas/pen/KzyLJZ

5. Отступы же всегда задаются снаружи элемента.
Перефразируем, «Отступы (margin) в обеих боксовых моделях (border-box и content-box), не влияют на значение width блока.»

6. Тонкости перевода, холивара ради,
— граница блока ≠ border блока, бордер — это border, а граница блока — это граница/край блока
— block area = область блока (читай размеры блока), но
— block area ≠ области ограниченной border'ом.
Тут стоит оговориться, наука наукой, а ежедневная работа вносит свои правки в лексикон разработчиков.
Спасибо за дополнения. Можете про первый пункт подробнее объяснить? Желательно с примерами вызова миксина.
Sign up to leave a comment.