От автора: эта статья является частью серии «CSS Grid Layout». В этом руководстве мы собираемся создать праздничный календарь CSS, для этого мы будем использовать CSS Grid, SVG и несколько праздничных изображений! Сначала посмотрите на то, что мы будем создавать.
Что нам понадобится
На самом деле в плане навыков для выполнения задания этого руководства вам понадобится не так и много — просто редактор кода (задействуйте CodePen, чтобы упростить себе задачу) и некоторые базовые знания по HTML и CSS. Однако вам нужны будут определенные визуальные материалы: я использовал очень красивые иллюстрации из Envato Elements (они векторные и абсолютно подходят для наших задач):
1. Добавление сетки
В нашем праздничном календаре мы будем использовать 25 элементов сетки; по одному на каждый из дней, предшествующих Рождеству, и один — для титульного рисунка. На маленьких экранах это будет выглядеть примерно так:
А так это будет выглядеть на больших экранах:
Бирюзовой элемент сетки будет содержать заголовок.
Разметка
В целом нам понадобятся 25 элементов в контейнере, поэтому давайте добавим соответствующий HTML-код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<section class='grid-1'> <div class='title'></div> <div class='day-1'></div> <div class='day-2'></div> <div class='day-3'></div> <div class='day-4'></div> <div class='day-5'></div> <div class='day-6'></div> <div class='day-7'></div> <div class='day-8'></div> <div class='day-9'></div> <div class='day-10'></div> <div class='day-11'></div> <div class='day-12'></div> <div class='day-13'></div> <div class='day-14'></div> <div class='day-15'></div> <div class='day-16'></div> <div class='day-17'></div> <div class='day-18'></div> <div class='day-19'></div> <div class='day-20'></div> <div class='day-21'></div> <div class='day-22'></div> <div class='day-23'></div> <div class='day-24'></div> </section> |
Совет. Учитывая повторяющийся характер этой разметки, вы можете предпочесть использовать язык шаблонов, такой как HAML. HAML позволяет перебрать 24 элемента, чтобы не пописывать каждый из них. Следующий небольшой фрагмент кода компилируется в то, что вы видите выше:
1 2 3 4 5 |
%section.grid-1 %div.title - (1..24).each do |i| %div{:class => "day-#{i}"} |
Когда мы будем размещать другие элементы в этих дивах, вы по достоинству оцените время, которое экономит для вас HAML!
Основные стили Grid
Давайте теперь добавим основные стили, чтобы задать сетку. Начнем с назначения display: grid; для элемента контейнера. Затем, после некоторых измерений, мы определяем элементы сетки.
1 2 3 4 5 6 7 8 9 10 11 12 |
/* макет сетки mobile first */ .grid-1 { display: grid; width: 96%; max-width: 900px; margin: 2% auto; grid-template-columns: repeat(3, 1fr); grid-template-rows: auto; grid-gap: 25px; } |
Мы используем подход «mobile first», поэтому в начале определяем только три столбца; для больших экранов мы используем отдельный медиа-запрос.
grid-template-columns: repeat(3, 1fr); дает нам три столбца, каждый из которых имеет равную ширину (часть 1fr)
grid-template-rows: auto; в принципе является значением по умолчанию, но это объявляет, что строки не будут иметь определенной высоты, мы можем добавить в них столько контента, сколько захотим, и они будут растягиваться вместе с ним.
grid-gap: 25px; определяет зазоры.
Это на самом деле все, что нам нужно. Grid этого уже достаточно, но мы конкретнее укажем, где должен размещаться каждый элемент. По этой причине мы будем использовать Grid Areas.
Grid Areas
Мы можем назначить имя для каждой области сетки, которую определили, и можем фактически прописать ее визуально:
1 2 3 4 5 6 7 8 9 |
grid-template-areas: "t t t" "d23 d20 d12" "d2 d14 d4" "d5 d22 d16" "d1 d7 d9" "d10 d11 d18" "d13 d3 d15" "d6 d17 d8" "d19 d24 d21"; |
Первую область, которая охватывает три столбца в первой строке, мы именуем t (в ней мы собираемся разместить заголовок). Это может быть не самое интуитивное имя, но сейчас оно нам подходит. Каждой из прочих областей мы присваивается имя в соответствии с номерами дней, и, как видите, мы можем разместить их там, где мы хотим. Возможность размещать элементы «случайно», как здесь, идеально подходит для праздничного календаря.
Переходим к адаптивности
Добавив медиа-запрос, мы можем (очень просто) изменить макет для больших экранов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* media query */ @media only screen and (min-width: 500px) { .grid-1 { grid-template-columns: repeat(6, 1fr); grid-template-areas: "t t t d2 d7 d8" "t t t d4 d11 d12" "t t t d19 d9 d13" "d6 d1 d24 d24 d21 d20" "d17 d18 d24 d24 d5 d22" "d3 d23 d16 d14 d10 d15"; } } |
С помощью этого медиа-запроса мы объявляем, что для окон просмотра шириной более 500 пикселей (произвольная цифра) мы изменяем сетку так, чтобы она имела шесть столбцов: grid-template-columns: repeat(6, 1fr);.
И мы можем полностью переопределить расположение элементов, разместив дни, где нам нравится. Вы заметите, что титульный блок теперь занимает три столбца и три строки в верхнем левом углу, а d24 занимает область 2 × 2, чтобы он больше выделялся. Это станет понятнее, когда на следующем шаге мы назначим элементы сетки для областей сетки.
Пока что мы не можем видеть ничего из того, что мы сделали, поэтому давайте добавим некоторые временные стили к элементам сетки, чтобы сделать их видимыми.
1 2 3 4 |
section div { background: #2e313d; padding: 40px; } |
Взгляните:
Назначение областей сетки
Теперь нам нужно назначить элементы сетки для областей, которые мы указали. Мы делаем это следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* отдельные элементы */ .title { grid-area: t; } .day-1 { grid-area: d1; } .day-2 { grid-area: d2; } .day-3 { grid-area: d3; } ... |
Вы можете видеть, что div.title был назначили для области сетки t, и каждый день был назначен для соответствующей области. Излишне напоминать, что вы, конечно, не можете назначить .day-3 в grid-area: d16;, мы просто организуем элементы таким образом. Вот, как это выглядит?
2. Открытие дверей
Это базовая структура, теперь нам нужно сделать в CSS двери. Мы собираемся поместить в каждый элемент сетки два div — один для передней части двери, другой для задней части — оба обернуты в другой div, и мы используем переключатель чек-бокс, чтобы переворачивать элемент и открывать дверь при нажатии на определенный день. Начнем с добавления метки, чек-боксов и дивов для каждого элемента сетки:
1 2 3 4 5 6 7 8 9 10 |
<div class='day-1'> <label> <input type='checkbox'> <div class='door'> <div class='front'>1</div> <div class='back'></div> </div> </input> </label> </div> |
Опять же, вам нужно сделать это для всех 24 элементов сетки. А это довольно большой кусок повторяющейся разметки длиной в 245 строк и большой кусок работы. Поэтому вы можете использовать HAML. Вот как это будет выглядеть:
1 2 3 4 5 6 7 |
%div{:class => "day-#{i}"} %label %input{ :type=>"checkbox" } .door .front #{i} .back |
После небольших изменений полей теперь все чек-боксы выглядят так:
Двери
Приготовься: то, что мы сейчас будем делать, является, возможно, самым сложным. Это значительный объем работы, но без него мы практически ничего не сможем сделать из того, что нам нужно. Поэтому наберитесь терпения. Мы собираемся задать определенные изменения с помощью 3D-преобразований.
Сначала мы скрываем чек-боксы, затем объявляем, что хотим, чтобы к меткам применялся определенный уровень перспективы (это обрабатывает perspective: 1000px;). Дочерние элементы меток будут отображаться в трехмерном пространстве с помощью transform-style: preserve-3d;, а не просто на плоскости. Затем мы используем некоторые стили Flexbox, чтобы обеспечить, чтобы метка заполняла всю доступную для нее область.
Некоторые стили для элемента .door (который имеет переднюю и заднюю стороны), которые устанавливают время перехода и описывают дальнейшее состояние:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* стили door */ .grid-1 input { display: none; } label { perspective: 1000px; transform-style: preserve-3d; cursor: pointer; display: flex; min-height: 100%; width: 100%; height: 120px; } .door { width: 100%; transform-style: preserve-3d; transition: all 300ms; border: 2px dashed transparent; } |
Передняя и задняя стороны
ОК, теперь сосредоточиться на передней и задней сторонах нашей двери.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.door div { position: absolute; height: 100%; width: 100%; backface-visibility: hidden; display: flex; align-items: center; justify-content: center; } .door .back { background-color: #2e313d; transform: rotateY(180deg); } |
Селектор .door div относится как к диву .front, так и к диву .back. Мы используем его, чтобы задать для них ширину и высоту в 100% контейнера .door и позиционировать абсолютно вверху слева. Правила Flexbox обеспечивают, чтобы содержимое внутри (число) было выровнено по центру, а правило backface-visibility: hidden; задает, чтобы определенная сторона не была видна, когда к нам лицом обращена обратная ей сторона. Это важно, так как затем мы уделяем внимание .back и устанавливаем для него вращение с помощью transform: rotateY(180deg);.
Теперь займемся веселыми вещами
Все это дало нам довольно крутой эффект. Мы будем использовать проверку состояния чек-бокса для перехода к определенной стороне. Когда мы нажимаем на метку (которая заполняет всю область сетки), то устанавливает или снимает флажок чек-бокса, даже если он не отображается. В зависимости от этого состояния мы изменяем, какой стороной обращен к нам элемент .door.
1 2 3 4 5 6 7 |
label:hover .door { border-color: #385052; } :checked + .door { transform: rotateY(180deg); } |
Первое правило описывает состояние наведения курсора. Второе правило задает, что, когда элемент .door получает состояние :checked, мы вращаем его на 180 градусов по оси Y (переворачиваем его). Все это создает эффект открывающейся двери!
3. Пора все украсить
Давайте все украсим. Первый визуальный элемент, который мы собираемся поместить в слот — это заголовок. Используя иллюстрацию Счастливые дети, празднующие Рождество, я получил заголовок, изменил определенные параметры и сохранил файл SVG.
Совет. Для векторных изображений, подобных этим, в Illustrator перейдите Объект> Контур> Упростить … и вы можете уменьшить детализацию. Срезав определенное количество кривых и точек, вы можете значительно уменьшить размер файла, сохранив в целом общий эффект.
Есть несколько способов добавить это изображение на страницу, но я просто добавил в разметку тег img:
1 2 3 |
<div class='title'> <img src='merry-gridmas.svg'> </div> |
Некоторые стили задают гибкость изображения и выравнивают его по центру области сетки:
1 2 3 4 5 6 7 8 9 10 |
.title { display: flex; align-items: center; justify-content: center; } .title img { width: 90%; height: auto; } |
Чтобы улучшить пустой фон, мы через CSS добавляем в область сетки еще один SVG (снегопад и облака):
1 2 3 4 |
body { background: url(snow-bg.svg) no-repeat top center #82d8cb; background-size: cover; } |
Добавление изображений для дверей
У каждой из наших 24 дверей также должно быть изображение, скрывающееся за ней. Опять же, мы могли бы сделать это несколькими способами, но в данном случае я просто сохраняю кучу файлов SVG и добавляю их в качестве фона через CSS. После того как мы определим для каждой двери область сетки, у нас будет для нее правило для стороны .back:
1 2 3 4 5 6 |
.day-6 { grid-area: d6; } .day-6 .back { background: url(snowflake.svg); } |
Вот, что мы в результате получим:
Довольно неплохо! Теперь нам просто нужно улучшить эти изображения с помощью нескольких общих правила.
Завершающие штрихи
Во-первых, эти фоновые изображения должны отображаться только раз, без повторения, поэтому мы добавим no-repeat. Они также должны быть центрироваться и масштабироваться должным образом.
1 2 3 4 5 6 7 |
.door .back { background-size: contain; background-position: center center; background-repeat: no-repeat; background-color: #2e313d; transform: rotateY(180deg); } |
Определенный радиус углов границы, добавленный для .door и .door div, дает нам более эстетичный внешний вид. И, наконец, мы ссылаемся на шрифт Kalam, чтобы внести завершающий штрих.
1 |
<link href="//fonts.googleapis.com/css?family=Kalam" rel="stylesheet"> |
Стили:
1 2 3 4 5 6 |
/* добавляются к .door div */ font-family: 'Kalam', cursive; color: #385052; font-size: 2em; font-weight: bold; text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.2); |
Заключение
Что можно сказать в заключении? Конечно, эту демо-версию можно еще улучшить (статус каждой двери не сохраняется для следующего сеанса браузера или другие вещи), но мы итак проделали хорошую работу.
Поддержка — это последний вопрос, который следует упомянуть; есть несколько аспектов, использованных в этом руководстве, которые пока не полностью поддерживаются браузерами. Некоторые советы относительно того, как решить данную проблему, вы найдете в приведенных ниже ресурсах.
Надеюсь, вам понравилось это руководство, наслаждайтесь результатом!
Автор: Ian Yates
Источник: //webdesign.tutsplus.com/
Редакция: Команда webformyself.