Это вольный перевод недавней статьи Ömer Aslanbakan с добавлениями и сокращениями.

Проблема фронтенда в том, что мы не контролируем среду, в которой выполняется наш код: браузеров много и они могут отображать страницу очень по-разному. Часто мы вынуждены дописывать стили для конкретных браузеров или Internet Explorer, а иногда отдавать разным браузерам разные таблицы стилей. И хотя времена IE6 минули, вопрос прицельного действия на конкретный браузер не потерял актуальности.

Я собираюсь поделиться с вами LESS- и SASS-примесями, помогающими писать стили, нацеленные на конкретные браузеры или устройства. Это может оказаться полезным в дополнение к определениям возможностей браузера.

Javascript

Вставьте одну строчку JS-кода в секцию head или как можно выше в body . Этот код добавит тегу html дата-атрибут со строкой юзерагента.

<script>
  document.documentElement.setAttribute('data-browser', navigator.userAgent);
</script>

К примеру, на Windows 10 (x64) в браузере Chrome эта строка на момент написания статьи выглядит так:

Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36

Соответственно, после срабатывания кода имеем:

<html data-browser="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36">

SASS- и LESS-примеси

Приведенные SASS- и LESS-примеси позволят набирать меньше кода при написании специфичных стилей для браузеров или устройств. Примеси создают CSS-селектор, отталкивающийся от тега html , имеющего полное описание юзерагента в дата-атрибуте. Можно привязать стили к мобильным устройствам, WebKit-браузерам, продукции Apple и т.п. Примеси чувствительны к регистру символов.

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

SASS

@mixin browser($browsers: Mozilla) {
  @each $browser in $browsers {
    html[data-browser*="#{$browser}"] & {
      @content;
    }
  }
}

LESS

В LESS, увы, нет циклов без рекурсии. Чтобы сделать код простым и понятным, воспользуемся небольшим дополнением, реализующим циклы без прямого контакта с рекурсией — less.curious

@import "for.less"; // Импортируем файл, реализующий удобные циклы
 
 
.browser(@browser: Mozilla, @content) {
  .for(@browser);
  .-each(@value) {
    html[data-browser*="@{value}"] & {
      @content();
    }
  }
}

Использование

SASS-примесь: пример для Andriod-устройств

.btn-download {
  display: block;
  width: 100%;

  @include browser(Android) { // Скроем для Android
    display: none;
  }
}

Результат компиляции этого фрагмента:

.btn-download {
  display: block;
  width: 100%;
}
html[data-browser*="Android"] .btn-download {
  display: none;
}

SASS-примесь: пример для Internet Explorer 11

.selector:before {
  content: 'Browser';

  @include browser("MSIE 11") {
    content: 'IE';
  }
}

Результат компиляции:

.selector:before {
  content: 'Browser';
}
html[data-browser*="MSIE 11"] .selector:before {
  content: 'IE';
}

LESS-примесь: пример для iPhone и iPad

.main-nav {
  margin: 0;
  
  a {
    display: block;
    .browser("iPad" "iPhone", {
      display: inline-block;
    });
  }
}

Результат компиляции:

.main-nav {
  margin: 0;
}
.main-nav a {
  display: block;
}
html[data-browser*="iPad"] .main-nav a {
  display: inline-block;
}
html[data-browser*="iPhone"] .main-nav a {
  display: inline-block;
}

Заключение

Статья была бы неполной без справочника по юзерагентам.

И да, селекторы вида [attribute*="..."] — не самые быстрые CSS-селекторы, однако спекуляции на тему их «медленной» работы высосаны из пальца.

Дополнение от Николая Громова

Эта техника должна использоваться с осторожностью, если Вы планируете дописывать таким образом правила, нуждающиеся в вендорных префиксах (в рамках кроссбраузерности проекта), т.к. легко может получиться, что стили, написанные для IE старых версий вдруг обрастут вендорными префиксами для Chrome или Firefox.

Думаю, лучше всего использовать данный прием для коррекции проблем и привязки стилей к типу устройств. К примеру, можно скорректировать проблему смещения базовой линии подключённого к странице шрифта для OSX:

.btn {
  .browser("Mac OS X", {
    line-height: 1;
  });
}

А Вы что делаете чаще — определяете возможности браузера с помощью modernizr или сам браузер/OS?