Как стать автором
Обновить

Комментарии 44

Мне больше нравится, когда задан margin-top, а не margin-bottom
И обнулять, как правило, ничего не приходится, т.к. отступ у блока сверху обычно больше, чем между его элементами. Его тоже прописываем как margin-top. Результирующий будет только один, который больше.
По своему опыту вёрстки в Ворде (извиняюсь, если оскорбил чьи-то чувства) могу сказать, что если отступы абзаца снизу, то вечные косяки и постоянно приходится допиливать документ до приличного вида напильником. Те самые «последние элементы группы». А если абзац рулит отступом перед собой, то сразу всё красиво. И потом меньше проблем при редактировании.

Сколько сложностей. Проще же элементам списка дать половинный margin, а контейнеру половинный padding.


ul {
    padding: .5rem;
}
li {
    margin: .5rem;
}

У любой строки текста из-за line-height будет отступ сверху и снизу, который вы никак не уберёте (вариант с line-height=1 как правило не катит ибо не дружит с переносом текста). То есть вам в любом случае придётся учитывать, что у некоторый блоков будут симметричные отступы сверху и снизу. Поэтому лучше сразу всё и делать на симметричных отступах. Это и кода меньше займёт и лучше дружит с переносами блоков на новую строку.

По поводу отступов между однородными элементами. Самый правильный метод:
.block__item + .block__item {
    margin-top: 1em;
}

Никаких last-child и прочего. Нужно придерживаться принципа, что стили должны как можно реже отменяться и переопределяться. То есть вместо «задать всем, а потом последнему отменить» нужно действовать по методу «задать сразу тем, кому нужно». Это и сокращение количества стилей (меньше рябит в глазах от каскада в девтулс), и семантически правильнее.
Я стараюсь не пользоваться "+", а то он может организовать разные нежданчики.
Надо было в cms для лендинга завести поле для подзаголовка. Все шло нормально, прописала в шаблоне, что надо выводить поле с таким-то именем, и обернула в тег
<h2 class="subtitle"></h2>
Смотрю у подзаголовка нарисовались отступы, хотя все стили скинуты ресетом. В стилях класса «subtitle» я ни чего подобного не писала. Стерла «subtitle», а отступы есть. Поменяла на «h3» — все норм. Начала более внимательно просматривать какие стили применяются и нашла что-то вроде:
h1 + h2 { margin: 10px;}
Так тут не плюс виноват, а навешивание стилей на теги. Надо пользоваться БЭМ-ом.
Что досталось, новые страницы уже, конечно, верстали по БЭМ.
Здесь критерием скорее служит отсутствие лишнего маргина, нежели направление.
Отступы идут в направлении потока дом дерева, блок сам себя не толкает.

Единственный аргумент в пользу первого пункта и не выдерживает никакой критики.
Блок себя не толкает, а вот элемент блока (как например элемент списка, где сам список является блоком) вполне себя толкает, в зависимости от своего контекста, а именно в зависимости от того что за элемент находится перед ним. В CSS нельзя задать зависимость от последующих элементов, но можно от предыдущих, в том и смысл задавать в таких случаях margin именно что левый и верхний.

Кстати о смысле, какой смысл в том что элемент толкает что-то от себя вправо или вниз? Не особо большой, если вообще есть, не находите? Не чувствуется ли куда ли больший смысл в том что элемент может отталкиваться от чего-нибудь? Почувствуется, если задуматься ненадолго. В каком коде больше смысла, как думаете?

1.
.list {}
.list__item {
    // ... whatever else

    margin-bottom: 10px;

    &:last-child {
        margin-bottom: 0;
    }
}


2.
.list {}
.list__item {
    // .. whatever else

    & + & {
        margin-top: 10px;
    }
}
Не чувствуется ли куда ли больший смысл в том что элемент может отталкиваться от чего-нибудь?

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

Кроме того, даже если не брать во внимание семантический смысл, чисто технически задание отступа в зависимости от предыдущего элемента дает значительно большие возможности и свободу стилизации без необходимости хаков/усложнений или изменений в верстке. Вот, например, ситуация:
.list__item {
    & + & {
        margin-top: 2px;
    }
    &--big + & {
        margin-top: 4px;
    }

    & + &--big {
        margin-top: 10px;
    }
    &--big + &--big {
        margin-top: 20px;
    }   
}

У элемента отступ от предыдущего 2 или 4 пикселя, в зависимости от того, что это за предыдущий элемент: list__item или list__item--big. И у элемента отступ от предыдущего 10 или 20 пикселей, в случае если этот элемент сам list__item или list__item--big, плюс аналогично все так же есть зависимость от вида предыдущего элемента.
Получились, так сказать, правила взаимодействий.
А теперь как реализовать данные отступы, если мы будем задавать нижний отступ и что-нибудь обнулять? Никак. Нижние отступы и обнуления это просто-напросто недостаточный набор инстументов для реализации в данном случае. При этом контекстно зависимые верхние отступы в данном случае более чем достаточный набор инстументов.

Однако ситуаций много разных, требования к проекту и верстке тоже везде разные, где-то нужна поддерживаемость, где-то нужно как можно проще или как можно непробиваемее, не везде возможно сочетать все плюсы и обойтись без минусов, где нужны именно что нижние отступы по о-очень замысловатым причинам, где-то комбинация их или даже супер-замысловатая и сложноподдерживаемая комбинация. Тем не менее, несмотря на все многообразие возможных ситуаций, если говорить о наиболее предпочтительном способе задания отступов для большинства случаев — это именно что отступы вверх и влево. Преподанный же автором «известный стандарт» задания отступов является несомненно известной вещью, вот только не стандартом, а крайне часто применяемым и крайне редко уместным или предпочтительным методом задания отступов, приводящим к более серьезным ошибкам верстки и более сложному процессу их исправления.
Ну кстати да — не существует ведь селектора, зеркального плюсовому.
    & + & {
        margin-top: 2px;
    }
    &--big + & {
        margin-top: 4px;
    }

    & + &--big {
        margin-top: 10px;
    }
    &--big + &--big {
        margin-top: 20px;
    }   

Для тех, кто собирает имена классов по кусочкам (что в css, что в js) — есть отдельный котёл в аду.

Насчет имен согласен, а что насчет модификаторов?

А чем модификаторы хуже?

Модификаторы на то и модификаторы, что их названия не являются определяющими основное семантическое значение ни блока, ни элемента в блоке. Псевдоклассы :last-child, :first-child и тому подобные делают ровно ту же самую работу что и модификаторы в большинстве случаев, однако, я уверен, что вы не будет выступать против собирания конструкций с псевдоклассами вот такого рода:
.list__item {
    &:first-child {
        // .. whatever
    }
}


Так что вопрос тут действительно в том «а чем модификаторы хуже?», только относится он к псевдоклассам — чем модификаторы хуже псевдоклассов? Чем они хуже, что за их собирание через &-- нужен отдельный котел в аду?

Я избегаю таких конструкций из-за того, что они не ищутся поиском.
Например: хочу в коде найти где определяется правило для класса .list__item--big, и не найду его. А если я новый человек на проекте и еще не изучил особенности кода, то это может стать причиной бага.

На мой взгляд, это очень малый компромис, который стоит того — искать классы без учета модификаторов. Кроме того такие вещи все-таки оговариваются с новыми разработчиками на проекте, вдобавок к сотне других мелких вещей. А вот в незнакомом проекте лично я ищу полнотекстовым поиском вообще все что возможно reasonably найти: имя блока отдельно, имена элементов в блоке, отдельно модификаторы, все вместе, и даже части их, если это имеет смысл в конкретной ситуации. А все потому что неизвестно какой был контроль кода на незнакомом проекте, был ли он вообще, и были там какие-либо правила в принципе. Если же известно что там все четко и какие правила, то нет такой необходимости искать неизвестно что. Если контроль кода соблюдался четко, то собирание модификаторов не представляет никакой сложности для поиска использования класов. Однако в js и верстке я бы избегал даже собирания модификаторов настолько, насколько это возможно, но тоже не догматично.
Я пытаюсь писать sass как можно проще. Чтоб новый человек, и я старый мог легко вникнуть в проект. Конечно все оговаривается, но иногда кажется, что сасс используется ради сасса, а не для упрощения работы.
Мне понравился доклад Вадима Макеева на эту тему.
В том, насколько новый человек (или тот же самый человек, что писал код, но в будущем) будет понимать код, принимают участие большое количество факторов, и простота стилей заключается не только в том применяются возможности препроцессора или нет.
В данном случае вопрос был в использовании оператора & для сборки модификаторов. При использовании чистого css вместо scss не поменяется ни порядок задания правил, ни их логика, только синтаксис и единственный уровень вложенности. И это как раз та ситуация, где когнитивная нагрузка от дополнительного уровня абстракции в виде синтаксиса scss является достаточно малой, для того чтобы плюсы от его наличия перевешивали и снижали суммарный уровень нагрузки.

Грубо говоря плюсов настолько больше по сравнению с минусами конкретно в ситуации с оператором & и модификаторами с псевдоклассами, что практически не бывает ситуаций где чистый css выиграл бы по сравнению с этим. По поддерживаемости, пониманию кода, написанию кода и т.д…

Одно, пожалуй, требование — от человека работающего с этим кодом будет ожидаться знание и понимание css. Неважно новый он на проекте и видел ли sass до этого.

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

Специально для вас, кусочек типичного кода, который получается у средней руки программиста при попытке следования БЭМ-у и экономии на нажатиях клавиш (ведь именно в этом основное преимущество &, да?)


.panel-report
  min-width 700px
  height 100%

  &__head
    justify-content center
    align-content center
    min-height 40px
    margin 10ps
    padding 10px
    background $panel-head

  &__head-title
    color $panel-title
    text-align left
    max-width 50%
    padding 10px
    overflow hidden

    & > h1
      font-weight normal
      white-space nowrap
      padding 10px
      margin 0
      overflow hidden
      text-overflow ellipsis
      font-size: 20px

  &__wrapper
    width 100%
    display flex

    &--center
      .bench__blocks
        justify-content center

  &__blocks
    width 100%
    display flex

  &__block
    margin 10px
    border 1px solid $panel-border
    border-radius 4px
    background $panel-block-bg
    font-size 14px
    max-width 50%
    flex 1
    display flex
    flex-direction column

  &__title
    font-size 16px
    overflow hidden
    flex 0 0 60px
    display flex
    align-items center

    &--info
      cursor pointer
      user-select none

      &:hover
        background $hover-bg

        &:before
          content '['
          font-family monospace
          margin-left -1ch

        &:after
          content ']'
          font-family monospace
          margin-right -1ch

    &--text
        line-height 20px
        font-weight 600
        padding 10px
        color $panel-text
        text-align center
        overflow hidden
        text-overflow ellipsis
        flex 1 1 auto

  &__content
    padding 8px
    background $panel-value-bg
    margin 12px
    margin-top 0
    border 1px solid $panel-border
    border-radius 4px
    display flex
    flex-direction column
    flex 1 1 auto

  &__entity
    line-height 25px
    height 25px
    color $panel-text

    & > th
      font-weight normal

  &__entity-head
    vertical-align middle

  &__entity-row
    vertical-align middle

    & > em
      font-style normal

  &__power
    width 20px
    padding 0 6px

    &:after
      content '.'

  &__pos
    min-width 34px
    text-align right
    padding 0 6px

  &__name
    text-align right
    white-space nowrap
    text-overflow ellipsis
    overflow hidden
    font-size inherit
    max-width 180px

  &__val
    text-align right
    font-size inherit
    padding-left 8px

  &__br
    height 25px
    width 1px
    display block
    background $panel-border

  &__bar
    background-color $panel-bar-blue
    border none
    margin 0
    height 15px
    float left

    &.oil
      background-color $panel-bar-orange

  &__marker
    position relative
    margin auto
    cursor pointer
    flex 0 0 46px

  &__marker-indicator
    width: 34px;
    height: 34px;
    position: relative;
    background-size: 34px 34px

Все имена изменены, все совпадения случайны.


Сколько времени вам понадобится, чтобы найти место объявления стилей для следующего селектора?


.panel-report__title--info:hover:before
Секунд 10. Потому что используя БЭМ, конечно же, нужно искать по имени блока, а не всему селектору целиком.

И 2 встречных вопроса:
1. Как часто приходится искать такие селекторы?
2. Если писать всё полностью, то зачем вам препроцессор в принципе? Проще нативный CSS использовать.
Вот прежде чем использовать препроцессор, действительно нужно понять, зачем он вам нужен. Как и на нативном, так и на препроцессоре, можно говнокодить
Это общие слова, философия. Чуть конкретнее хотелось бы :)

10 секунд — довольно быстро для "дойти до нужной директории, найти нужный файл, найти нужное место в файле не запутавшись в контекстах".


А были бы селекторы целиком — вы бы нашли искомое за пару секунд через ctrl+shift+f.


  1. Когда правишь баги вёрстки — очень часто. Когда новый код пишешь, конечно ничего искать не надо.


  2. Так многие (и я в том числе) уже отказались от препроцессоров в пользу css-next.
Угу, то есть в процессе правки стилей селекторы ищутся каждый раз «с нуля»? Поправил одно свойство и закрыл, а потом снова отправился искать?
Нет, конечно, когда я работаю с каким-то блоком, я сразу ищу и открываю соответствующий ему файл. И дальше он у меня перед глазами, элементы и состояния ищутся легко.

Применимость css-next для меня не вполне понятна, потому что с одной стороны в ней нем многих реально нужных вещей (которые есть в препроцессорах), но зато есть много очень передовых (но не так уж необходимых) рюшечек из будущих спецификаций и костыльный синтаксис вложенности.
Я, право же, ярый противник как sass-синтаксиса, так и собирания имен классов. А вот scss-синтаксис, и собирание модификаторов к имени класса я как раз и одобряю, при некоторых условиях конечно.

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

Тот код, что вы привели в качестве примера ужасного кода, действительно ужасен по многим параметрам и это очень печальная ситуация, если «программист средней руки» пишет стили таким образом.

А как вам вот такая переработка этого же кода? Видите ли вы в нем существенные минусы из-за собирания модификаторов через &--, и сложно ли в нем будет найти стили селектора .panel-report__title--info:hover:before?

Код в scss со сборкой только модификаторов и псевдоклассов/псевдоэлементов
.panel-report {
    min-width: 700px;
    height: 100%;
    }
    .panel-report__head {
        justify-content: center;
        align-content: center;
        min-height: 40px;
        margin: 10ps;
        padding: 10px;
        background: $panel-head;
        }
        .panel-report__head-title {
            color: $panel-title;
            text-align: left;
            max-width: 50%;
            padding: 10px;
            overflow: hidden;
    
            & > h1 { // ! Спорное решение
                font-weight: normal;
                white-space: nowrap;
                padding: 10px;
                margin: 0;
                overflow: hidden;
                text-overflow: ellipsis;
                font-size: 20px;
                }
            }
        
    .panel-report__wrapper {
        width: 100%;
        display: flex;

        &--center {
            .bench__blocks { // ! Здесь явно пошло что-то не так в БЭМ
                justify-content: center;
                }
            }
        }
    
    .panel-report__blocks {
        width: 100%;
        display: flex;
        }
        .panel-report__block {
            margin: 10px;
            border: 1px solid $panel-border;
            border-radius: 4px;
            background: $panel-block-bg;
            font-size: 14px;
            max-width: 50%;
            flex: 1;
            display: flex;
            flex-direction: column;
            }
        
    .panel-report__title {
        font-size: 16px;
        overflow: hidden;
        flex: 0 0 60px;
        display: flex;
        align-items: center;

        &:hover {
            // Добавлено для иллюстрации взамного расположения
            }
        &:before {
            // Аналогично
            }
        &:after {
            // Аналогично
            }
        
        &--info {
            cursor: pointer;
            user-select: none;

            &:hover {
                background: $hover-bg;

                &:before {
                    content: '[';
                    font-family: monospace;
                    margin-left: -1ch;
                    }
                &:after {
                    content: ']';
                    font-family: monospace;
                    margin-right: -1ch;
                    }
                }
            }

        &--text {
            line-height: 20px;
            font-weight: 600;
            padding: 10px;
            color: $panel-text;
            text-align: center;
            overflow: hidden;
            text-overflow: ellipsis;
            flex: 1 1 auto;
            }
        }
    
    .panel-report__content {
        padding: 8px;
        background: $panel-value-bg;
        margin: 12px;
        margin-top: 0;
        border: 1px solid $panel-border;
        border-radius: 4px;
        display: flex;
        flex-direction: column;
        flex: 1 1 auto;
        }
    
    .panel-report__entity {
        line-height: 25px;
        height: 25px;
        color: $panel-text;

        & > th {
            font-weight: normal;
            }
        }
        .panel-report__entity-head {
            vertical-align: middle;
            }
        .panel-report__entity-row {
            vertical-align: middle;

            & > em { // ! Нужен ли здесь > ?
                font-style: normal;
                }
            }
        
    .panel-report__power {
        width: 20px;
        padding: 0 6px;

        &:after {
            content: '.';
            }
        }
    .panel-report__pos {
        min-width: 34px;
        text-align: right;
        padding: 0 6px;
        }
    .panel-report__name {
        text-align: right;
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
        font-size: inherit;
        max-width: 180px;
        }
    .panel-report__val {
        text-align: right;
        font-size: inherit;
        padding-left: 8px;
        }
    .panel-report__br {
        height: 25px;
        width: 1px;
        display: block;
        background: $panel-border;
        }
    .panel-report__bar {
        background-color: $panel-bar-blue;
        border: none;
        margin: 0;
        height: 15px;
        float: left;

        &.oil { // ! Что-то здесь не то
            background-color: $panel-bar-orange
            }
        }
    .panel-report__marker {
        position: relative;
        margin: auto;
        cursor: pointer;
        flex: 0 0 46px;
        }
        .panel-report__marker-indicator {
            width: 34px;
            height: 34px;
            position: relative;
            background-size: 34px 34px;
            }


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

И конкретно это место в коде можно написать несколькими вариантами в рамках все тех же правил, но уже это не касается модификаторов, а только сборки сочетаний :before и :hover. Вот, например, один из них:

Другой вариант :hover:before
&--info {
    cursor: pointer;
    user-select: none;

    &:before,
    &:after {
        display: none;

        font-family: monospace;
        }
    &:before {
        content: '[';

        margin-left: -1ch;
        }
    &:after {
        content: ']';

        margin-right: -1ch;
        }

    &:hover {
        background: $hover-bg;

        &:before,
        &:after {
            display: block;
            }
        }
    }

Проблема поиска очень сильно преувеличена.
На практике искать определения классов (имеется в виду по всему проекту) приходится на пару порядков реже, чем писать. Так что лучше вынести общее имя блока за скобки, чем городить его несколько десятков раз, создавая почву для опечаток и ошибок копипаста.
Да и не нужно быть семи пядей во лбу, чтобы догадаться поискать по имени блока без модификатора — эта мысль приходит на автомате любому человеку, хоть сколько-нибудь понимающему БЭМ. Новый человек, не новый — не играет роли в данном случае. В самом крайнем случае — спросить!
Нет не на хожу никакого «смысла».
Список здесь представлен как простой пример, так как сложный в разы дольше разбирать.
Забудьте про список и про равные итемы.
Возьмем для примера это:

Отступ от заголовка к дате 20 пикселей.
Или для вас отступ от даты к заголовку 20 пикселей?
Если снести эту дату.
То отступ от заголовка станет уже 30 пикселей или для вас такой расклад приемлем? никогда не приходилось потом подгонять нужный отступ?

Не приходится подгонять если смотреть на верстку комплексно и со смыслом. Отступы не существуют сами по себе, это не самостоятельные сущности.

Судя только по картинке и не зная бизнес-логику и другие возможные комбинации элементов в этом блоке, могу предположить разбиение на блоки и отступы примерно вот так:
image

1. Заголовок — никаких отступов никуда
2. Дата+Статус, назовем этот блок Контент — никаких отступов никуда, но если Контент идет после Заголовка, то делаем отступ вверх
3. Чат — никаких отступов никуда, но если идет после Контента, то отступ до Контента тот что на скриншоте. Если возможна такая ситуация что Контента нет, а Чат есть, то мы легко можем дописать отступ вверх от Чата до Заголовка

А вот что происходит внутри Контента и какие там между собой отступы у элементов внутри уже дело самого блока Контент, но принцип остается тот же.

Понимаете теперь что смысл ищется исходя из, так сказать, бизнес-логики блоков, и что отступам желательно реализовывать именно что бизнес-логику, а не выравнивание по дизайну? (За выравнивание по дизайну отвечает размер отступа, а не факт его наличия/отсутствия и не условие его наличия/отсутствия)

Никогда не приходилось увольнять крикоруких дизайнеров, которые лепят отступы от балды?

Ваши принципы разобьются когда контент-менеджер будет заполнять страницу, и перед каким нибудь должен быть отступ больше чем перед параграфом. Он не будет делать специальные обертки, а повставляет простые
.
Конечно можно прописать p + h2{...}, p + p{...}, но тогда ваши стили будут ужасны для всех.
Для верстки «через админку», эти принципы конечно не подходят.
Больная тема для многих, кто занимается разработкой интерфейсов.
Причем это все можно стандартизировать.
Или может быть уже есть таковые стандарты?
Сколько раз сталкивался с проблемами padding и margin, особенно когда несколько человек делают front-end. Впору брошюру делать )
По большему счету, стандартов, как таковых, не существует. Это больше похоже на культуру написания. Но люди любят делать отсебятину.
Это «головная боль» фронтенд разработчика. Подпишусь под комментарием, возможно, что-то кто-то расскажет. А еще лучше — есть ли набор неких «лучших практик» с учетом современных flex и grid по позиционированию елементов?
Такое впечатление что автор пишет только одностраничники или сайты с постоянным контентом. «Сбрасывайте отступы у последних элементов», «задавайте margin-bottom»… Боже, да если б я такое творил меня б мой контентменеджер повесил за причинное место. Только margin-top, если ты прописываешь margin-bottom, то на это должна быть серьезная причина (Пример — хлебные крошки, или элемент между main и footer). Работаем сверху вниз, слева на право. А если контента по какой-то причине не будет? Ну не подключил человек модульный элемент из админки. Всё? Переписываем верстку, или вы выдумываете велосипеды под все случаи жизни с добавлением «классов затычек».
:last-child или :not(:last-child), конечно же, вы не используете?
И, опять же, как решают указанные проблемы замена margin-bottom на margin-top?
Добавил небольшой перечень исключений
Тю, я думал здесь будет что-то эх какое, судя из заголовка и первого абзаца. Наверное, я что-то забыл? А оказалось, это набор ваших правил, которые у меня вызвали больше WTF, чем понимания зачем вы так делаете.
Не моих, мною озвученных. Здесь описана четкая модель.
Чтоб понять зачем, наверное надо с эти поработать.
Вы считаете, я не работаю с вёрсткой? Преимуществ в вашей схеме я не вижу вообще
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории