Довольно часто наши любимые дизайнеры делают в макетах кнопки разных размеров и величин, некоторые из которых повторяются, некоторые нет. Неплохо было бы организовать систему для быстрого добавления и редактирования этих самых кнопок, в чем на могут помочь sass @extend's. Приведу небольшую иллюстрацию кнопок в типичном проекте.



Как не надо делать


HTML для наших кнопок будет неизменным в течение всей статьи:

<ul class="about_butt_list">
    <li class="about_butt_item"><a href="#" class="about_butt blue_mod">Инфраструктура</a></li>
    <li class="about_butt_item"><a href="#" class="about_butt red_mod">Квартиры</a></li>
    <li class="about_butt_item"><a href="#" class="about_butt yellow_mod">Галерея</a></li>
</ul>

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

SCSS:

.about_butt {
	display: block;
	height:50px;
	line-height: 50px;
	text-align: center;
	font-family: 'intro';
	font-size: 12px;
}

Мы написали стили для нашего основного класса, теперь сделаем его модификации по цвету(для цвета использованы переменные для удобства):

.about_butt {
	display: block;
	height: 50px;
	line-height: 50px;
	text-align: center;
	font-family: 'intro';
	font-size: 12px;

	&.blue_mod {
		background: $blue_1;
		color: $white;
		transition: background .3s ease;

		&:hover, &:focus {
			text-decoration: none;
		}

		&:hover {
			background: lighten($blue_1, 5%);
		}
	}
	&.red_mod {
		background: $red_1;
		color: $white;
		transition: background .3s ease;

		&:hover, &:focus {
			text-decoration: none;
		}

		&:hover {
			background: lighten($red_2, 5%);
		}
	}
	&.yellow_mod {
		background: $yellow_1;
		color: $white;
		transition: background .3s ease;

		&:hover, &:focus {
			text-decoration: none;
		}
	}
}

Пока все просто и понятно.Но на следующей странице появляется вот такая кнопка:



Эта кнопка имеет те же размеры, что и предыдущие, но другое оформление. Давайте нарушим принцип DRY и скопируем стили для нее от наших предыдущих кнопок:

.news_more_butt {
	display: block;
	height:50px;
	line-height: 50px;
	text-align: center;
	font-family: 'intro';
	font-size: 12px;
}

С размерами определились, давайте добавим оформление:

.news_more_butt {
	color:$black_2;
	background: transparent;
	box-shadow:inset 0 0 0 2rem $gray_4;
	transition:all .3s ease;

	&:hover,&:focus {
		text-decoration: none;
	}

	&:hover {
		background: $gray_4;
		color:$white;
	}
}

Ну и немного стилей для размещения нашей кнопки:

.news_more_butt {
	width: 186px;
	margin: 20px auto;
}

Идем дальше и на другой странице встречаем следующую кнопку:



Оформление осталось прежним, а вот размеры кнопки и шрифта изменились. И тут перед нами два пути:

  1. Продолжать копировать стили для разных кнопок и давать им уникальные классы
  2. Сделать специальные классы для оформления и добавлять его в наши теги

Минусы каждого из этих подходов очевидны. В первом мы копируем слишком много кода, и когда нужно что-либо изменить — менять нужно в нескольких местах. Во втором мы добавляем презентационные классы, и это тоже не очень хорошо(любители Bootstrap бы возразили).
Но есть и третий путь — использование sass @extend(хотя это можно реализовать в любом препроцессоре).

Третий путь


У меня примеси лежат в отдельном scss файле — buttons.scss, это крайне удобно.Мы будем разделять их на размеры(+типографика) и цветовые схемы.Напишем классы для размеров:

%butt_size_1 {
	display: block;
	height:50px;
	line-height: 50px;
	text-align: center;
	font-family: 'intro';
	font-size: 12px;
}

%butt_size_2 {
	display: block;
	height:70px;
	line-height: 70px;
	text-align: center;
	font-family: 'intro';
	font-size: 16px;
}

Отлично, а теперь цветовые схемы:

%butt_gray_1 {
	color: $black_2;
	background: transparent;
	box-shadow: inset 0 0 0 2rem $gray_4;
	transition: all .3s ease;

	&:hover, &:focus {
		text-decoration: none;
	}

	&:hover {
		background: $gray_4;
		color: $white;
	}
}

%butt_blue_1 {
	background: $blue_1;
	color: $white;
	transition: all .3s ease;

	&:hover, &:focus {
		text-decoration: none;
	}

	&:hover {
		background: lighten($blue_1, 5%);
	}
}

%butt_red_1 {
	background: $red_2;
	color: $white;
	transition: all .3s ease;

	&:hover, &:focus {
		text-decoration: none;
	}

	&:hover {
		background: lighten($red_2, 5%);
	}
}

%butt_yellow_1 {
	background: $yellow_1;
	color: $white;
	transition: all .3s ease;

	&:hover, &:focus {
		text-decoration: none;
	}

	&:hover {
		background: lighten($yellow_1, 5%);
	}
}

%butt_green_1 {
	background: $green_1;
	color: $white;
	transition: all .3s ease;

	&:hover, &:focus {
		text-decoration: none;
	}

	&:hover {
		background: lighten($green_1, 5%);
	}
}

Вот мы и получили гибкую систему для организации наших кнопок.Теперь наш scss будет выглядеть следующим образом:

.about_butt {
	@extend %butt_size_1;
	&.blue_mod {
		@extend %butt_blue_1;
	}
	&.red_mod {
		@extend %butt_red_1;
	}
	&.yellow_mod {
		@extend %butt_yellow_1;
	}
}
.news_more_butt {
	@extend %butt_size_1;
	@extend %butt_gray_1;

	width: 186px;
	margin: 20px auto;
}
.show_news_butt {
	@extend %butt_size_2;
	@extend %butt_gray_1;

	display: inline-block;
}


Если появляется новая цветовая схема — мы просто делаем для нее @extend и используем, если изменяется текущая — ругаемся на дизайнера правим в одном месте.

Ключевые моменты


  • Используем тихие классы, а не миксины(меньше результирующего CSS)
  • Если у вас одно-страничный сайт с небольшим количеством кнопок — данная система будет излишней
  • В тихих классах объявляется display:block, потом это можно переписать в правиле селектора


P.S.: Данную систему разработал Андрей Бойко, за что ему огромное спасибо!

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


  1. kvaps
    20.11.2015 11:24

    Что-то шрифт кнопок на картинке плывет, сначала попробовал глаза протереть, нет, правда плывет…


    1. kvaps
      20.11.2015 11:30

      Статья кстати классная, спасибо. Не знал что такое на css можно.


      1. DeXPeriX
        20.11.2015 11:41

        Это же не CSS, а один из препроцессоров — SASS. После компиляции из SASS получается CSS.
        Смысл лично мне не очень понятен. В SASS есть примеси, переменные. Их надо использовать. Что ещё можно вынести из статьи?


        1. gatilin222
          20.11.2015 14:06

          Когда я начинал верстать, сам бы не додумался до такой системы, и мне кажется статья полезна для таких как я)
          Мне бы было интересно посмотреть ваши наработки в sass, если есть возможность поделитесь.


  1. asci
    20.11.2015 11:40

    вы же знаете что `butt` по-английски значит, правда?)
    А вообще спасибо, сам над чем-то похожим думаем в проекте. Но пока решили сделать несколько базовых миксинов и просто передавать в них цвета


    1. gatilin222
      20.11.2015 13:23

      Я не знал, если честно, довольно-таки смешно получается)


  1. Metaller
    20.11.2015 11:50

    Хорошо бы вам подучиться нормальному стилю кода или хотя бы использовать IDE с автоформатированием. В свойствах после двоеточего пробел то есть, то нет, вместо табуляции используйте 4 пробела, оступы огромные. несколько extend можно объединять в одной строке @extend .foo, .bar.

    Откуда такие размеры и зачем тут rem если везде px width: 186rem; margin: 20rem auto;? По умолчанию 1rem = 16px.

    Эти же классы нельзя будет применить на <button>, будут дефолтные бордеры.

    Маленький лайфхак transition:all .3s ease; можно заменить на transition: .3s ease;, но если вы меняете только одно свойство, то лучше указать его явно transition: background-color .3s ease; чтобы избежать ненужных анимаций.

    Ну и последнее в этом занудном комментарии — сокращать имя класса button до butt странно, коллеги не поймут (butt — анг. задница), общепринято btn.


    1. Metaller
      20.11.2015 13:21

      А еще у вас в классах смесь теплого и мягкого. Если это класс size, зачем там же переопределяется font-size, font-family, text-align, display. Если это цвет, зачем там переопределяется transition. Вынесите все общие для кнопок свойства в общие, и расширяйте для каждой кнопки.


      1. gatilin222
        20.11.2015 13:31

        Мне и моим коллегами удобнее делать 2 тихих класса)


        1. Ag47
          20.11.2015 13:43

          Сейчас у вас в тихих классах размеров и тем, куча копипасты про шрифт, танзишен и т.д., если понадобиться менять, вы предлагаете менять те же настройки транзишена в пяти местах, а если цветов еще больше, то в еще большем количестве. Зачем код так жестоко дублировать то?

          Если он везде пристуствует его можно вынести в отдельный тихий класс %btn-default и extend делать либо в нужных классах кнопок, либо в сами тихие классы им расширить. Хотя, конечно, стоило просто завести класс btn c свойствами по-умолчанию, не стоит слишком увлекаться extend'ами.


          1. gatilin222
            20.11.2015 13:59

            Вы правы, нужно все загонять в переменные, но для этой статьи я решил немного упростить)
            А так все зависит от конкретного проекта, здесь описаны основные моменты


            1. Ag47
              20.11.2015 14:02

              Тогда лучше было выкинуть совсем не относящиеся к делу стили=)


              1. gatilin222
                20.11.2015 14:04

                Наверное так и надо было сделать, не бейте сильно — это первый опыт написания чего-то осмысленного)


          1. Glivera
            20.11.2015 19:58

            В данном примере описана система которая обычно используется на больших проектах. Размер кнопки подразумевает подкласс объекта который включает в себя общие свойства для нескольких кнопок. По сути каждый «класс size» это дефолтное состояние для набора кнопок с определенной высотой. Вся система построена на том что бы иметь только один класс в HTML для привязки всех стилей и не завязываться на модификаторы.


    1. faiwer
      20.11.2015 13:27

      вместо табуляции используйте 4 пробела, оступы огромные

      О_о, очередной tabs-vs-spaces?


      1. Metaller
        20.11.2015 13:30

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


        1. faiwer
          20.11.2015 13:31

          Наглядный пример чего? Пример default-го tabSize-а в браузере? Вы серьёзно?


          1. Metaller
            20.11.2015 13:33

            Как один из кейсов. Дефолтный tabSize в браузере у 99% пользователей. Код выше с такими отступами выглядит неаккуратно. Давайте не будем начинать?

            PS И кстати при чем тут tabSize браузера, стили для кода — это CSS хабра.


            1. faiwer
              20.11.2015 13:38

              Дык, какое отношение имеет дефолтный tabSize в браузере к написанию CSS-кода? Вы выше даёте советы использовать вместо табов пробелы… Я могу точно также рекомендовать всем использовать пробелы, вместо табов. НО!

              Зачем вы (не конкретно вы, а апологеты пробелов) из раза в раз тащите всю эту вкусовщину на хабр? Вам этого мало?


            1. gatilin222
              20.11.2015 13:46

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


            1. gatilin222
              20.11.2015 13:47

              Ответил выше)


    1. gatilin222
      20.11.2015 13:30

      Вы правы, в оформлении кода есть косяки, которые образовались во время переноса из редактора в статью).
      Надо бы поменять rem на px(где-то изменил, а где-то нет).
      transition обычно определяю в тихом классе, для статьи переписал.У меня на проектах 1rem = 10px.
      Видимо коллеги находятся на моем уровне грамотности и понимают, что butt — это кнопка, хотя и вправду получается смешно)


  1. sashabeep
    20.11.2015 13:09

    Прям новшество лабораторий гарнье :)
    Написал один сайт на компасе + кучка своих примесей — разучился писать css
    еще бы кто предложил компилятор компаса, чтобы на шареде бегало, а то при любых изменениях пересобирать и закидывать — пока что не самая интересная процедура. Не надо, пожалуйста, рассказывать про всякие там VPS, серверы, облака и колокейшены — цель должна оправдывать средства


  1. lifecom
    20.11.2015 13:22

    Очень удобный велосипед!


  1. Pilat
    20.11.2015 13:49

    Я как не-верстальщик понял только одно: надо пользоваться стандартными кнопками Bootstrap и ничего не трогать :)


    1. gatilin222
      20.11.2015 14:02

      Если это работает на ваших проектах, совершенно верно! Просто на моих проектах css-фреймворки не едут)


  1. firya
    20.11.2015 15:00

    Следующим шагом предлагаю посмотреть в сторону БЭМ и не бояться написать для кнопки лишний класс.
    Можно сократить итоговый css раза в полтора использовав для кнопки классы размера, и миксины просто станут не нужны.


    1. gatilin222
      20.11.2015 17:38

      У кнопки делаю один основной класс — мне так удобно, не люблю много презентационных классов)


      1. firya
        20.11.2015 18:00

        Вы итак используется модификационные классы для цвета, чем вам помешает еще один класс для размера?
        Из плюсов:

        • почти в 3 раза меньше стилей
        • такой код легче сопровождать и поддерживать

        и выглядеть это будет примерно так:
        Код (656 символов стилей)
        Код на вскидку, не проверял идентичность
        <a href="#" class="btn btn-blue">Инфраструктура</a>
        <a href="#" class="btn btn-red">Квартиры</a>
        <a href="#" class="btn btn-yellow">Галерея</a>
        <a href="#" class="btn btn-transparent">Архив новостей</a>
        <a href="#" class="btn btn-transparent btn-xl">Показать все новости</a>
        

        .btn {
        	display: block;
        	height: 50px;
        	line-height: 50px;
        	text-align: center;
        	font-family: 'intro';
        	font-size: 12px;
        	text-decoration: none;
        	background: transparent;
        	transition: background .3s ease;
        
        	&.btn-blue {
        		background-color: #80B1D3;
        
        		&:hover {
        			background: #80B1D3;
        			color: #fff;
        		}
        	}
        
        	&.btn-red {
        		background-color: #D46C6B;
        
        		&:hover {
        			background: #D46C6B;
        			color: #fff;
        		}
        	}
        
        	&.btn-yellow {
        		background-color: #F3B562;
        
        		&:hover {
        			background: #D46C6B;
        			color: #fff;
        		}
        	}
        
        	&.btn-transparent {
        		box-shadow: inset 0 0 0 2rem $gray_4;
        	}
        
        	&.btn-xl {
        		height: 70px;
        		line-height: 70px;
        		font-size: 16px;
        	}
        }
        


        1. gatilin222
          20.11.2015 20:21

          Прочитайте чуть выше комментарий Glivera


  1. PeoneEr
    20.11.2015 17:22

    А зачем Вы каждой кнопке говорите

    &:hover, &:focus {
    text-decoration: none;
    }

    ?
    Задайте это свойство основному классу, а если вдруг потребуется — лучше его изменить для одного стиля, чем тащить везде.


    1. gatilin222
      20.11.2015 17:37

      один раз написал его в екстенде — и не парюсь, зачем мне его постоянно писать? А переопределить всегда смогу у основного класса


  1. Arkasha
    22.11.2015 19:15

    Надо посмотреть на БЭМ и CSSComb