CSS-сетка и поэтапное улучшение
Весной 2017 года мы впервые увидели, как в браузеры практически одновременно попала такая важная спецификация, как сетка, и теперь поддержка CSS-сетки есть в общедоступных версиях Firefox, Chrome, Opera, Safari и Edge. Однако, хотя современные браузеры означают, что многие из нас очень быстро увидят, что большинство пользователей будут поддерживать макет сетки, также есть старые или неподдерживающие браузеры. В этом руководстве мы рассмотрим различные стратегии поддержки.
Поддерживающие браузеры
CSS-сетка не имеет префиксов во всех современных браузерах. Поддержка всех свойств и значений, описанных в этих руководствах, совместима во всех браузерах. Это означает, что если вы напишете код макета сетки в Firefox, он должен работать таким же образом в Chrome. Это больше не экспериментальная спецификация, и вы можете безопасно использовать её в продакшене.
Можно ли безопасно использовать CSS-сетки для моего макета?
Да. Как и при любом выборе технологии front-end, решение использовать CSS-сетку будет зависеть от того, какие браузеры обычно используют посетители вашего сайта.
Начинаем использовать сетку в продакшене
Стоит отметить, что вы не обязаны использовать сетку в полном объёме. Начните с улучшения элементов вашего дизайна с помощью сетки, которые в противном случае могли бы отображаться с помощью более старого метода. Замена устаревших методов макетом сетки работает удивительно хорошо, благодаря тому, как сетка взаимодействует с этими другими методами.
Свойства floats
Свойства floats раньше использовались для создания макетов с несколькими колонками. Если вы поддерживаете старую кодовую базу с макетами, использующими свойства floats, никаких конфликтов не будет. Элементы сетки игнорируют свойство float; фактически, элемент сетки имеет приоритет. В примере ниже у меня простой медиа-объект. Если свойство float не удалено из устаревшего CSS, так как контейнер является контейнером сетки, это нормально. Мы можем использовать свойства выравнивания, реализованные в CSS-сетках.
Свойство float больше не применяется, и я могу использовать свойство CSS Box Alignment align-self для выравнивания моего содержимого по правому краю контейнера:
* {
box-sizing: border-box;
}
img {
max-width: 100%;
display: block;
}
.media {
border: 2px solid #f76707;
border-radius: 5px;
background-color: #fff4e6;
max-width: 400px;
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-areas: "img content";
margin-bottom: 1em;
}
.media::after {
content: "";
display: block;
clear: both;
}
.media .text {
padding: 10px;
align-self: end;
}
/* old code we can't remove */
.media .image {
float: left;
width: 150px;
margin-right: 20px;
}
<div class="media">
<div class="image">
<img src="https://dummyimage.com/150x150" alt="placeholder" />
</div>
<div class="text">
This is a media object example. I am using floats for older browsers and
grid for new ones.
</div>
</div>
На изображении ниже показан медиа-объект в браузере, не поддерживающем сетку (слева), и в браузере, поддерживающем её (справа):
Использование запросов на функциональность
Приведённый выше пример очень простой, и мы можем обойтись без написания кода, который будет проблемой для браузеров, не поддерживающих сетку, а устаревший код не представляет проблемы для браузеров, поддерживающих сетку. Однако, не всегда всё так просто.
Более сложный пример
В этом следующем примере у меня есть набор плавающих карточек. Я дал карточкам свойство width, чтобы float их. Чтобы создать промежутки между карточками, я использую свойство margin для элементов и отрицательное отступ для контейнера:
.wrapper ul {
overflow: hidden;
margin: 0 -10px;
padding: 0;
list-style: none;
}
.wrapper li {
float: left;
width: calc(33.333333% - 20px);
margin: 0 10px 20px 10px;
}
<div class="wrapper">
<ul>
<li class="card">
<h2>One</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Two</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Three</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Four</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Five</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Six</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
</ul>
</div>
Пример демонстрирует типичную проблему с макетами, использующими свойства floats: если к любой карточке добавить дополнительное содержимое, макет сломается.
В качестве уступки для старых браузеров я установил свойство min-height для элементов и надеюсь, что мои редакторы контента не добавят слишком много содержимого и не испортят макет!
Затем я улучшаю макет, используя сетку. Я могу превратить мой <ul> в контейнер сетки с тремя колонками. Однако, ширина, которую я задал для самих элементов списка, всё ещё применяется, и теперь эти элементы составляют треть ширины колонки:
Если я сброшу ширину до auto, это остановит поведение float для старых браузеров. Мне нужно задать ширину для старых браузеров и убрать ширину для браузеров, поддерживающих сетку. Благодаря запросам на функциональность CSS я могу сделать это прямо в CSS.
Решение с использованием запросов на функциональность
Запросы на функциональность будут очень знакомы, если вы когда-либо использовали запросы на медиа для создания адаптивного макета. Вместо проверки ширины viewport или каких-либо особенностей браузера или устройства, мы проверяем поддержку пары CSS-свойства и значения с помощью правила @supports. Внутри запроса на функциональность мы можем написать любой CSS, необходимый для применения современного макета, и удалить всё, что нужно для старого макета.
@supports (display: grid) {
.wrapper {
/* do anything for grid supporting browsers here. */
}
}
Запросы на функциональность отлично поддерживаются браузерами, и все браузеры, поддерживающие обновлённую спецификацию сетки, также поддерживают запросы на функциональность. Вы можете использовать их для решения проблемы с нашим улучшенным макетом, использующим свойства floats.
Я использую правило @supports для проверки поддержки display: grid. Затем я выполняю код сетки для <ul>, задаю ширину и min-height для <li> на auto. Я также удаляю отступы и отрицательные отступы и заменяю интервалы свойством gap. Это означает, что у меня нет конечного отступа в последней строке блоков. Теперь макет работает, даже если в одной из карточек содержится больше контента, чем в других:
.wrapper ul {
overflow: hidden;
margin: 0 -10px;
padding: 0;
list-style: none;
}
.wrapper li {
float: left;
width: calc(33.333333% - 20px);
margin: 0 10px 20px 10px;
}
@supports (display: grid) {
.wrapper ul {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin: 0;
}
.wrapper li {
width: auto;
min-height: auto;
margin: 0;
}
}
<div class="wrapper">
<ul>
<li class="card">
<h2>One</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Two</h2>
<p>We can use CSS grid to overwrite older methods.</p>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Three</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Four</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Five</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Six</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
</ul>
</div>
Переопределение других значений свойства display
Из-за проблем с созданием сеток элементов с помощью свойств floats многие из нас использовали бы другой метод, нежели метод с floats, для выкладки набора карточек. Использование display: inline-block является альтернативным методом.
Ещё раз я могу использовать запросы на функциональность для переопределения макета, использующего display: inline-block, и снова мне не нужно переопределять всё. Элемент, установленный на inline-block, становится элементом сетки, и поэтому поведение inline-block больше не применяется. Я использовал свойство vertical-align для моего элемента, когда режим отображения inline-block , но это свойство не применяется к элементам сетки и, следовательно, игнорируется, когда элемент становится элементом сетки:
.wrapper ul {
margin: 0 -10px;
padding: 0;
list-style: none;
}
.wrapper li {
display: inline-block;
vertical-align: top;
width: calc(33.333333% - 20px);
margin: 0 10px 20px 10px;
}
@supports (display: grid) {
.wrapper ul {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin: 0;
}
.wrapper li {
width: auto;
margin: 0;
}
}
<div class="wrapper">
<ul>
<li class="card">
<h2>One</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Two</h2>
<p>We can use CSS grid to overwrite older methods.</p>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Three</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Four</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Five</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
<li class="card">
<h2>Six</h2>
<p>We can use CSS grid to overwrite older methods.</p>
</li>
</ul>
</div>
Ещё раз, нам нужно обратить внимание на ширину элемента, а затем на любые другие свойства, которые мы хотим улучшить. В этом примере я снова использовал gap, а не отступы и отрицательные отступы, чтобы создать промежутки между элементами.
Как спецификация определяет эти переопределения?
Спецификация CSS-сетки подробно описывает, почему мы можем переопределять поведение определённых свойств, когда что-то становится элементом сетки. Ключевыми разделами спецификации являются:
Так как это поведение подробно описано в спецификации, вы можете безопасно полагаться на использование этих переопределений при поддержке старых браузеров. Ничто описанное здесь не должно рассматриваться как «взлом». Скорее, мы используем возможность взаимодействия различных методов макета, о которой подробно говорится в спецификации сетки.
Другие значения display
Когда у элемента родитель установлен на display: grid, он блокируется, как определено в спецификации CSS display. В случае с нашим элементом, установленным на inline-block, именно поэтому display: inline-block больше не применяется.
Если вы используете display: table для вашего устаревшего макета, элемент, установленный на display: table-cell, создаёт анонимные блоки. Поэтому, если вы используете display: table-cell без родительского элемента, установленного на display-table, вокруг любых смежных ячеек будет создан анонимный обертка таблицы, точно так же, как если бы вы обернули их в div или другой элемент, установленный на display: table. Если у вас есть элемент, установленный на display: table-cell, и затем в запросе функции вы меняете родителя на display: grid, создания анонимного блока не произойдёт. Это означает, что вы можете переопределить макеты display: table без дополнительных анонимных блоков.
Элементы с плавающей позицией
Вертикальное выравнивание
Свойство выравнивания vertical-align не оказывает влияния на элемент сетки. В макетах, использующих display: inline-block или display: table, вы можете использовать свойство vertical-align для базового выравнивания. В вашем макете сетки вы затем имеете гораздо более мощные свойства выравнивания блоков.
Макет с несколькими колонками
Вы также можете использовать макет с несколькими колонками в качестве плана для устаревшего браузера, так как свойства column-* не применяются, когда они применяются к контейнеру сетки.
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Grid_layout_and_progressive_enhancement