CSS Protips

Это современные решения типичных проблем, коллекция советов, которая поможет вам улучшить ваши профессиональные навыки CSS.

От переводчика

Приветствую, для вас подготовлен еще один перевод заметок на тему CSS. Мэтт Смит, разработчик из Портленда, поделился CSS-советами и выложил их на GitHub. Мне особенно понравилась его подборка, она структурирована, не особо громоздкая в плане скучных больших текстов и описаний, и в целом будет понятна даже новичку. Я буду рад, если в комментариях мы с вами обсудим каждый пункт и в итоге дадим некоторые заключения. Итак, приступим.



Cодержание


  1. Используем псевдо-класс :not для задания рамки навигации
  2. Добавляем межстрочный интервал элементу body
  3. Центрируем по вертикали все что угодно
  4. Правильно разделяем запятыми элементы списков
  5. Отрицательный порядковый номер в nth-child
  6. Используем SVG-логотипы
  7. Аксиоматический CSS
  8. Максимальная высота у CSS-слайдера
  9. Наследуем box-sizing
  10. Одинаковая ширина ячейки таблицы
  11. Динамические внешние отступы при помощи flexbox
  12. Используем селектор атрибутов пустых ссылок
  13. Стили по умолчанию для обычных ссылок


Используем псевдо-класс :not для задания рамки навигации


Вместо того, чтобы задавать рамку (border) таким образом…
/* добавляем рамку */
.nav li {
  border-right: 1px solid #666;
}

… да еще и обнулять border последнему элементу…
/* удаляем рамку */
.nav li:last-child {
  border-right: none;
}

… можно было просто использовать псевдо-класс :not(), который поможет нам выбрать только нужные элементы:
.nav li:not(:last-child) {
  border-right: 1px solid #666;
}

Конечно, вы могли использовать такую выборку .nav li + li или даже .nav li:first-child ~ li, однако, если мы намеренно используем :not(), нам ясно, что CSS определяет границу всем элементам, кроме последнего, и теперь любому человеку будет понятно, что здесь происходит. Этот способ поддерживается в IE9+ и остальных.

Добавляем межстрочный интервал элементу body


Вам не следует добавлять высоту строки для каждого параграфа или заголовка (<р>, <h*>), соответственно, определяя каждый элемент. Вместо этого, добавьте этот код в тело элемента body:
body {
  line-height: 1;
}

Вот таким вот образом, любые текстовые элементы наследуют это свойство от главного родительского элемента body.

Центрируем по вертикали все что угодно


Нет, это не черная магия, вы действительно можете центрировать любой элемент по вертикали:
html, body {
  height: 100%;
  margin: 0;
}

body {
  -webkit-align-items: center;  
  -ms-flex-align: center;  
  align-items: center;
  display: -webkit-flex;
  display: flex;
}

Хотите центрировать как-то еще? Вертикально, горизонтально… как-нибудь, где-нибудь? На CSS-Tricks вы можете ознакомиться со статьей и тогда вы сможете делать все, что угодно. Пример имеет поддержку в IE11+ и остальных.

Примечание: Следите за багами (ошибки) flexbox в IE11 и контролируйте процесс html-верстки.

Правильно разделяем запятыми элементы списков


Мы можем сделать наши элементы li так, чтобы они действительно выглядели как реальный список, записи которого разделены запятыми:
ul > li:not(:last-child)::after {
  content: ",";
}

Используя псевдо-класс :not(), мы добавляем после каждого элемента ul-списка запятую, кроме последнего.

Отрицательный порядковый номер в nth-child


Используем отрицательные аргументы в nth-child для выбора элементов с 1 по n.
li {
  display: none;
}

/* выбираем элементы с 1 по 3 и отображаем их */
li:nth-child(-n+3) {
  display: block;
}

Или, теперь, когда мы знаем все об использовании псевдо-класса :not(), можем попробовать так:
/* скрываем все элемента ul-списка, кроме элементов с 1 по 3 */
li:not(:nth-child(-n+3)) {
  display: none;
}

Ну, что, было довольно легко.

Используем SVG-логотипы


Нет, никаких причин не использовать SVG:
.logo {
  background: url("logo.svg");
}

SVG хорошо масштабируется под любое разрешение и поддерживается во всех браузерах, IE9+.Теперь мы можем использовать svg, вместо .png, .jpg, or .gif-файлов.

Примечание: Если у вас есть SVG-иконка только для какой-либо кнопки и, в случае, если SVG не был загружен, вы можете использовать доступную текстовую подсказку:
.no-svg .icon-only::after {
  content: attr(aria-label);
}


Аксиоматический CSS


Лоботомированная сова (аксиоматический СSS), да, это довольно странное название, однако с помощью универсального селектора (*) и одноуровневого селектора (+) можно получить мощные возможности CSS:
* + * {
  margin-top: 1.5em;
}

В этом примере, все элементы в потоке, которые расположены после другого элемента, должны получить верхний отступ равный 1.5em.Более подробную информацию о "лоботомированной сове" можете прочитать в статье Хейдона Пикеринга, или перевод на русском.

Максимальная высота у CSS-слайдера


Реализовать CSS-слайдер можно с помощью «max-height» и «overflow:hidden»:
.slider ul {
  max-height: 0;
  overflow: hidden;
}

.slider:hover ul {
  max-height: 1000px;
  transition: .3s ease; /* анимация для max-height */
}


Наследуем box-sizing


Пусть box-sizing наследуется от html:
html {
  box-sizing: border-box;
}

*, *:before, *:after {
  box-sizing: inherit;
}

Теперь нам проще контролировать box-sizing в плагинах или компонентах, которые используют свои правила поведения. Поддержка в IE8+ и остальных.

Одинаковая ширина ячейки таблицы


Иногда, таблицы могут причинять боль в работе, поэтому попробуйте использовать table-layout: fixed, чтобы задействовать ячейки одинаковыми по ширине:
.calendar {
  table-layout: fixed;
}

Мы избавляемся от боли с помощью table-layout. Поддержка в IE8+ и остальных.

Динамические внешние отступы при помощи flexbox


При работе с колоночным макетом, вы можете избавиться от использования css-селекторов nth-*, first-*, и last-child при помощи flexbox значения space-between:
.list {
  display: flex;
  justify-content: space-between;
}

.list .person {
  flex-basis: 23%; /* базовый размер отдельно взятого блока */
}

Поддержка в IE11+ и остальных.

Используем селектор атрибутов пустых ссылок


Отображаем ссылки, когда a-элемент не имеет текстового значения, но при этом атрибут href содержит ссылку:
a[href^="http"]:empty::before {
  content: attr(href);
}

Это довольно удобно. Поддержка в IE9+ и остальных.

Стили по умолчанию для обычных ссылок


Добавляем по умолчанию стиль ссылкам:
a[href]:not([class]) {
  color: #008000;
  text-decoration: underline;
}

Теперь ссылки, вставленные через визуальный редактор вашей CMS, которые обычно не имеют класса, будут отличаться от остальных ссылок, не затрагивая каскад.

Комментарии (28)


  1. Psychosynthesis
    19.01.2016 03:28
    +4

    Последнее не сильно отличается от обычного задания по тегу и в общем случае врядли будет сильно полезно.

    a { color: #008000; text-decoration: underline; }

    Вообще половина примеров — вполне себе элементарные знания, никаких особых хитростей тут нет. Особенно удивляет что кто-то может не знать 2 и 4.


    1. taliban
      21.01.2016 12:25
      +1

      Вы похоже не поняли последний стиль, он применится только тем ссылкам, которые не имеют класса, а не все подряд.


      1. Psychosynthesis
        28.01.2016 02:43
        +1

        Я понял, потому и написал «не сильно отличается». Не вижу этому применения при правильно выстроенной иерархии стилей в интерфейсе.


  1. Invision70
    19.01.2016 04:30
    +9

    Это все понятно, так что насчет дельных советов?


  1. dom1n1k
    19.01.2016 04:42
    +5

    Вам не следует добавлять высоту строки для каждого параграфа или заголовка
    Cледует.

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


  1. linoleum
    19.01.2016 06:22
    +4

    Лоботомированная сова… в продакшне так лучше не делать. Я уже вижу как другой разработчик тратит полчаса на «а откуда тут этот отступ». А когда найдет сову, то сам пойдёт делать лоботомию, угадайте кому.


    1. mayorovp
      19.01.2016 09:10
      +3

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

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

      Я бы не рискнул использовать подобные трюки без контекста (.enable-owl * > *)


  1. Dolios
    19.01.2016 11:31
    +1

    Надо, наверное, тоже начать куски букваря по css перепечатывать. Стану популярным автором :-)
    splincodewd все что есть в вашем посте, есть в любом учебнике по css. За исключением, разве что, трюка с «совой», который, впрочем, весьма дурно пахнет, имхо. Только у вас, в отличие от учебника, все разрозненно и бессистемно.

    Ваша статья даже вредна, я бы сказал. Вместо того, чтобы, например, прочитать главу про flexbox и разобраться с ним, новичок начитается вот таких статей, в которых ничего не объясняется и предлагается поверить в магию «хаков», и будет потом иметь проблемы.

    Желающим разобраться, советую какую-нибудь хорошую книгу почитать. Например, эту:
    www.allitebooks.com/css-the-missing-manual-4th-edition


  1. RUQ
    19.01.2016 12:02
    +1

    А вот я не понимаю. Flexbox, все круто, и пример про «Динамические внешние отступы при помощи flexbox», то есть вроде бы мечта сбылась. Просто говоришь ширину блока, и space-between, а оно уже само там.

    Но, что если у меня 6 блоков и на каком-то разрешении помещается в ряд 4. Что будет с оставшимися 2? А я вам скажу, они будут просто по краям. Как так...flexbox ведь?

    Я встречал какие-то странные хаки, дескать надо подставить несколько фальшивых (пустых блоков) до недостающего и тогда все будет ок, но это чушь. Другими словами, пока без inline-block никуда)


    1. Ganster41
      19.01.2016 13:15

      Media queries и flex-wrap вам в этом случае помогут.


      1. RUQ
        19.01.2016 13:33
        +1

        В том-то и дело, что я ожидал от flexbox, решения простой задачи равномерного распределения ячеек в зависимости от ширины. А вместо этого мне предлагают завязываться на физические величины (media-queries). Flex-wrap — тут не при чём.

        На мой взгляд оптимальным решением было-бы, например специальное свойство для последней строки, наверное.


        1. SelenIT2
          19.01.2016 14:35
          +2

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


        1. AlexKeller
          19.01.2016 18:39

          Может, я не совсем корректно вас понял насчет последней строки, но простейший флекс позволяет сделать так:

          image


    1. vintage
      19.01.2016 20:12

      Не понял, а что ещё вы ожидали от space-between? Вам точно он нужен, а не какой-нибудь margin-right: calc( 10% + 10px )?


      1. RUQ
        20.01.2016 10:07

        Не от space-between, и даже не от space-around. А ожидал от flexbox решения простой задачи распределения карточек с фиксированной шириной и например фиксироваными отступами по центру контейнера + каждая карточка должна быть одинакова по высоте (по контенту самой большой карточки).

        Ваше предложение, её кстати тоже не решает, так как карточки будут выровнены по левому краю контейнера. Посмотрите как это решается например в twitter bootstrap — отрицательные маргины у контейнера.

        Возможно как вариант взять от flexbox stretch по поперечной оси, а всё остальное от сетки из inline-block'ов.


        1. vintage
          20.01.2016 12:29

          margin: 0 calc( 10% + 10px )?

          Нарисуйте картинку лучше.


          1. RUQ
            20.01.2016 13:21

            Я же говорю в вашем случае блоки будут по левому краю. Лучшая картинка, хм ну например так:

            .container
                .child
                .child
            
            


            .conatainer
                text-align: center
                margin: 0 -15px;
            
            .child
                display: inline-block
                width: 300px
                margin: 0 15px;
            
            


            Как-то так, таким образом дочерние элементы всегда будут по центру и равно-удалённы от друг друга, в отличие от вашего предложения когда они выровнены по левому краю .container.

            P.S. Чувствую себя занудой.


          1. RUQ
            20.01.2016 13:26

            Короче я дозанудничал, если вы имеете ввиду margin: 0 calc( 10% + 10px ) для блоков внутри flex-контейнера, без всяких там space-between, то таки да, скорее всего это оно.


  1. locky_yotun
    19.01.2016 12:42
    +1

    Вот так можно выровнять по вертикали что угодно без использования flexbox, абсолютного позиционирования и таблиц: jsfiddle.net/locky/ueen3L3k


    1. Vend3tta
      19.01.2016 16:20

      1. locky_yotun
        19.01.2016 16:38

        Ну понятно, что метод стар как все знают что. Но это не отменяет того, что в среднем по миру по данным caniuse IE8 и IE9, которые ни в каком виде нативно не поддерживают flexbox, дают пока еще 2%. Это уже значительная доля, которую нужно принимать во внимание, если мы не говорим о разработке одностраничного лендинга. Ну а на отдельных ресурсах их доля может быть и выше.


        1. SelenIT2
          19.01.2016 18:13

          Во-первых, не поддерживают нативно, но с прошлого декабря есть полифилл. Во-вторых, если у 2% пользователей страница будет почти как у взрослых, но без вертикального выравнивания — думаю, ни эти 2%, ни кто-либо еще не умрет. В третьих, неизвестно, сколько из этих 2% — боты:)


  1. xargon
    19.01.2016 17:08

    По поводу слайдера — не совсем понятно, что имеется ввиду.


    1. c01nd01r
      19.01.2016 19:23
      +1

      Что-то вроде details в HTML5


    1. SelenIT2
      20.01.2016 08:53

      Есть мнение, что «слайдер» в данном случае — это баян аккордеон)


  1. jmaks13
    19.01.2016 17:22
    +1

    Прочитав статью вспомнил студента проходившего у меня практику. Я его как то спросил где нужно использовать класс clearfix, на что он ответил, что на всякий случай ставит его везде.


  1. sashabeep
    20.01.2016 00:05
    -2

    Dead owl описывали на ALA очень много лет назад

    Хочу про списки вспомнить, точнее, про то, что должно отмереть. Лично мое имхо — с тех пор, как появилась возможность делать маркированные списки в html никакие дурацкие разделители не нужны, кроме копирования исконно литературного вида (куда это перекочевало из рукописей), когда в начале элемента списка ставится какое-нибудь тире типа "—", а в конце — ";". Делалось это в рукописях только для того, чтобы понять, где закончился один элемент и начался второй, маркеры и отступ списка для этих целей самодостаточны сами по себе.

    • Ну это же видно
    • невооруженным взглядом

    Равно как и то место, где список закончился.


    1. SelenIT2
      20.01.2016 08:52

      Списки разные нужны, списки разные важны. Бывают задачи типа такой.