Pull to refresh

Адаптивная верстка с помощью SCSS и Gulp

Reading time 4 min
Views 17K
Доброго времени суток, коллеги!

Давно задавался вопросом, как оптимизировать и сделать более удобным код используя @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;

Всем спасибо за внимание, и заранее за комментарии!
Tags:
Hubs:
+10
Comments 23
Comments Comments 23

Articles