Доброго времени суток, коллеги!
Давно задавался вопросом, как оптимизировать и сделать более удобным код используя @media screen
. Ибо код
body{font-size: 1em;}
@media screen and (max-width: 1024px){
body{font-size: 0.8em;}
}
создает достаточно крупные файлы. Конечно, можно написать миксин вроде respond-to(tablet), его многие используют и выглядит он приятней и удобней чем выше описанный вариант, но основную проблему он не решает. В крупных проектах получим уйму @include
и разобраться не то чтобы сложно, но приходится много карулесить по файлу, в поисках нужного класса или вложения.
И как же все таки получить читаемый, ну или как минимум файл в два или даже в три раза меньше? Такой вопрос я задавал себе, и пришел к ответу:
«Сделать возможным прописывать все разрешения в одну строку, т.е. не дублировать значения.»
В итоге должно получиться что-то вроде
body{font-size: [1em, 0.8em]}
где первое значение [1em] — для всех экранов, а второе [0.8em] для экранов меньше 1024px. Согласитесь, такой вариант значительно упрощает жизнь и уменьшает файл в разы, легко описывает правило для всех разрешений.
На первый вопрос ответ найден. А вот другой вопрос, как этого добиться? Первая мысль была написать модуль для Gulp, который бы переносил значения из [] в @media screen
… Но такой вариант не очень хорош, так как во-первых, это достаточно сложный процесс. Нужно многое продумать, уметь делать не конфликтующие модули, в общем, в моем случае это проблематично. Во-вторых, такой синтаксис не воспримет ни один idea, и подобные выходки будут подчеркиваться красным, что тоже не есть хорошо.
Поэтому я решил что @mixin
в Sass вариант подходящий, хоть и не такой изящный и читабельный как использование []. И так, вот что у меня получилось:
/*Прописываем массив нужных размеров*/
$screens: (all, 1024, 640);
@mixin media($property, $values){
/*разбиваем введенные значения в цикле*/
@for $i from 1 through length($values) {
/*Проверяем, если значение прописано как '' тогда пропускаем его*/
@if nth($values, $i) != ''{
@if nth($screens, $i) == 'all'{
/*Если это первое значение, тогда значение пропишется без @media screen */
#{$property}: unquote(#{nth($values, $i)});
} @else {
/*иначе помещаем свойство в @media screen с соответствующим индексом*/
@media screen and (max-width: nth($screens, $i) + 'px') {
#{$property}: unquote(#{nth($values, $i)});
}
}
}
}
}
Тепер вызвать миксин можно таким образом:
body{
@include media(font-size, (1em, 0.8em));
}
CSS:
body{font-size: 1em;}
@media screen only (max-width: 1024px){
body{font-size: 0.8em;}
}
Вроде бы как получили нужный результат, но так только кажется, без дополнительных модулей для Gulp не обошлось. Когда я описал несколько правил
body{
@include media(font-size, (1em, 0.8em, 0.6em));
@include media(color, (black, green, red));
}
.class{
@include media(display, (none, block, none));
}
в итоге получил не лучший CSS:
body{font-size: 1em;}
@media screen only (max-width: 1024px){
body{font-size: 0.8em;}
}
@media screen only (max-width: 640px){
body{font-size: 0.6em;}
}
body{color: black;}
@media screen only (max-width: 1024px){
body{color: green;}
}
@media screen only (max-width: 640px){
body{color: red;}
}
.class{display:none;}
@media screen only (max-width: 1024px){
.class{display:block;}
}
@media screen only (max-width: 640px){
.class{display:none;}
}
От дублирования @media screen only (max-width: 1024px)
нужно как-то избавляться. Для этого я установил модуль для Gulp — gulp-group-css-media-queries, описание по установке здесь
Результат:
body{font-size: 1em;}
body{color: black;}
.class{display: none;}
@media screen only (max-width: 640px){
body{font-size: 0.6em;}
body{color: red;}
.class{display: none;}
}
@media screen only (max-width: 1024px){
body{font-size: 0.8em;}
body{color: green;}
.class{display: block;}
}
Так намного лучше, но все равно не хорошо, так как каждое значение описывается повторно с новым элементом body. В решении этой проблемы мне помог модуль gulp-minify-css, описание здесь.
И вуаля:
body{
font-size: 1em;
color: black;
}
.class{display: none;}
@media screen only (max-width: 640px){
body{
font-size: 0.6em;
color: red;
}
.class{display: none;}
}
@media screen only (max-width: 1024px){
body{
font-size: 0.8em;
color: green;
}
.class{display: block;}
}
Получаем идеальный css используя минимум строк в Sass. Я использую Gulp+Sass, но для любителей Less+Webpack или Sass+Compass, или в любой другой связке, думаю не будет проблем переписать миксин и найти нужные модули.
Сам я сразу протестировал свой вариант на не столь крупном проекте, но все же править пришлось достаточно много, в результате я остался доволен процессом. Единственное что, не очень удобно, при использовании большого количества разрешений появляется такого рода код:
.class{
@include media(color, (red, '', '', '', green, black));
@include media(width, (50%, '', '', '', '', 100%));
}
В таком случае по началу немного теряешься и не всегда понятно для какого экрана правишь, но это не было проблемой или неудобством для меня (открыл, проверил, поменял). В случае если у вас 2-3 разрешения, выглядеть все будет читабельно и лаконично, хоть и не привычно по началу.
Вывод
Данным миксином я добился желаемого результата, все варианты экранов в одну строку. Конечно код сыроват, и возмножно что-то подобное уже написанно кем-то куда лучше чем это сделал я, но я не нашел, может плохо искал. В любом случае буду рад услышать ваше мнение по данному методу. Может кто-то знает что-то по-лучше, или знает как приукрасить данный метод, пишите. Возможно я написал полную ересь, и вы никогда не будете исользовать данный метод потому что… В таком случае прошу обосновать почему, для меня важно понять насколько может быть полезен/бесполезен данный метод.
P.S.
Для тех кто решил опробовать, хочу уточнить что если вы используете сокращенные свойства типа маrgin: 0 auto;
, тогда «0 auto» обязательно нужно взять в кавычки, иначе получите margin: 0;
Всем спасибо за внимание, и заранее за комментарии!
Автор: HTML-coder