Spec-Zone.ru › CSS

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>

На изображении ниже показан медиа-объект в браузере, не поддерживающем сетку (слева), и в браузере, поддерживающем её (справа):

A simple example of overriding a floated layout using grid. Both have the image aligned left. The text is vertically aligned at top in the float example and at the bottom in the grid example.

Использование запросов на функциональность

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

Более сложный пример

В этом следующем примере у меня есть набор плавающих карточек. Я дал карточкам свойство 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: если к любой карточке добавить дополнительное содержимое, макет сломается.

A floated cards layout demonstrating the problem caused by uneven content height. The top row has 3 cards. The fourth card is floated under the third card. Then a bottom row has contains the fifth and sixth cards. There is a largish empty space under the fourth card.

В качестве уступки для старых браузеров я установил свойство min-height для элементов и надеюсь, что мои редакторы контента не добавят слишком много содержимого и не испортят макет!

Затем я улучшаю макет, используя сетку. Я могу превратить мой <ul> в контейнер сетки с тремя колонками. Однако, ширина, которую я задал для самих элементов списка, всё ещё применяется, и теперь эти элементы составляют треть ширины колонки:

Six very tall, very narrow grid items with text overflowing on the right. After applying grid to our container, the width of the items is now incorrect as they display at one third of the item width.

Если я сброшу ширину до 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-сетки подробно описывает, почему мы можем переопределять поведение определённых свойств, когда что-то становится элементом сетки. Ключевыми разделами спецификации являются:

  • Создание контейнеров сетки
  • Элементы сетки
  • Отображение элементов сетки

Так как это поведение подробно описано в спецификации, вы можете безопасно полагаться на использование этих переопределений при поддержке старых браузеров. Ничто описанное здесь не должно рассматриваться как «взлом». Скорее, мы используем возможность взаимодействия различных методов макета, о которой подробно говорится в спецификации сетки.

END_OF_DOCUMENT_MARKER ```

Другие значения 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 без дополнительных анонимных блоков.

Элементы с плавающей позицией

Как мы уже видели, float и также clear не имеют эффекта на элемент сетки. Поэтому вам не нужно явно устанавливать элементы в float: none.

Вертикальное выравнивание

Свойство выравнивания 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API