Масштабирование изображений в сетке PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.

Масштабирование изображений в макете сетки

Создать сетку изображений легко благодаря CSS Grid. Но заставить сетку делать причудливые вещи после изображения были размещены, может быть сложно осуществить.

Скажем, вы хотите добавить какой-нибудь причудливый эффект наведения к изображениям, где они увеличиваются и масштабируются за пределы строк и столбцов, в которых они расположены? Мы можем это сделать!

Круто, правда? Если вы проверите код, вы не найдете ни JavaScript, ни сложных селекторов, ни даже магические числа. И это только один пример из многих, которые мы рассмотрим!

Построение сетки

Код HTML для создания сетки так же прост, как список изображений в контейнере. Нам не нужно больше, чем это.

<div class="gallery">
  <img>
  <img>
  <img>
  <!-- etc. -->
</div>

Для CSS мы сначала начнем с настройки сетки, используя следующее:

.gallery {
  --s: 150px; /* controls the size */
  --g: 10px;  /* controls the gap */

  display: grid;
  gap: var(--g);
  width: calc(3*var(--s) + 2*var(--g)); /* 3 times the size plus 2 times the gap */
  aspect-ratio: 1;
  grid-template-columns: repeat(3, auto);
}

Короче говоря, у нас есть две переменные, одна из которых управляет размером изображений, а другая задает размер промежутка между изображениями. aspect-ratio помогает сохранить пропорции.

Вам может быть интересно, почему мы определяем только три столбца, но не строки. Нет, я не забыл строки — нам просто не нужно их явно задавать. CSS Grid может автоматически размещать элементы на неявные строки и столбцы, что означает, что мы получаем столько строк, сколько необходимо для любого количества изображений, которые мы ему подбрасываем. Вместо этого мы можем явно определить строки, но нам нужно добавить grid-auto-flow: column чтобы убедиться, что браузер создаст для нас необходимые столбцы.

Вот пример, иллюстрирующий оба случая. Разница в том, что один течет в row направление и другое в column направлении.

Узнать подробности эта другая статья, которую я написал для получения дополнительной информации о неявных сетках и алгоритме автоматического размещения.

Теперь, когда у нас есть сетка, пришло время стилизовать изображения:

.gallery > img {
  width: 0;
  height: 0;
  min-height: 100%;
  min-width: 100%;
  object-fit: cover;
}

Эффект наведения, который мы делаем, зависит от этого CSS. Возможно, вам покажется странным, что мы делаем изображения, которые не имеют ни ширины, ни высоты, но имеют минимальную ширину и высоту, равные 100%. Но вы увидите, что это довольно ловкий трюк для того, чего мы пытаемся достичь.

Что я здесь делаю, так это сообщаю браузеру, что изображения должны иметь 0 ширина и высота, но также должны иметь минимальную высоту, равную 100%… но 100% которого? При использовании процентов значение равно относительно чего-то другого. В этом случае наше изображение помещается внутри ячейка сетки и нам нужно знать этот размер, чтобы знать, что 100% является относительным.

Браузер сначала проигнорирует min-height: 100% для вычисления размера ячеек сетки, но он будет использовать height: 0 в его расчете. Это означает, что наши изображения не будут влиять на размер ячеек сетки… потому что технически они не имеют физического размера. Это приведет к трем равным столбцам и строкам, которые основаны на размере сетки (которую мы определили на .galleryширина и aspect-ratio). Высота каждой ячейки сетки не что иное, как переменная --s мы определили (то же самое для ширины).

Масштабирование изображений в макете сетки

Теперь, когда у нас есть размеры ячеек нашей сетки, браузер будет использовать их с min-height: 100%min-width: 100%), что заставит изображения полностью заполнить пространство каждой ячейки сетки. Все это может показаться немного запутанным, но основная идея состоит в том, чтобы убедиться, что сетка определяет размер изображений, а не наоборот. Я не хочу, чтобы изображение определяло размер сетки, и вы поймете, почему после добавления эффекта наведения.

Создание эффекта наведения

Что нам нужно сделать, так это увеличить масштаб изображений при наведении курсора. Мы можем сделать это, настроив изображение width и height on :hover:

.gallery {
  --f: 1.5; /* controls the scale factor */
}

.gallery img:hover{
  width:  calc(var(--s) * var(--f));
  height: calc(var(--s) * var(--f));
}

Я добавил новую пользовательскую переменную, --f, в качестве коэффициента масштабирования для управления размером при наведении. Обратите внимание, как я умножаю переменную size, --s, чтобы вычислить новый размер изображения.

Но вы сказали, что размер изображения должен быть равен 0. Что происходит? Я потерян…

То, что я сказал, по-прежнему верно, но я делаю исключение для зависшего изображения. Я говорю браузеру, что только одно изображение будет иметь размер, отличный от нуля, поэтому оно будет вносить вклад в размерность сетки, а все остальные останутся равными 0.

Масштабирование изображений в сетке PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.
Масштабирование изображений в макете сетки

Левая сторона показывает сетку в ее естественном состоянии без каких-либо наведенных изображений, что и показывает правая сторона. Все ячейки сетки слева имеют одинаковый размер, так как все изображения не имеют физических размеров.

С правой стороны наведено второе изображение в первой строке, что придает ему размеры, влияющие на размер ячейки сетки. Браузер будет увеличивать эту конкретную ячейку сетки при наведении курсора, что влияет на общий размер. А так как задан размер всей сетки (потому что мы задаем фиксированный width на .gallery), другие ячейки сетки будут логично реагировать, становясь меньше, чтобы сохранить .galleryобщий размер в такт.

Это наш эффект масштабирования в действии! Увеличивая размер только одного изображения, мы влияем на всю конфигурацию сетки, и мы говорили ранее, что сетка определяет размер изображений, так что каждое изображение растягивается внутри своей ячейки сетки, чтобы заполнить все пространство.

К этому мы добавляем немного transition И использовать object-fit чтобы избежать искажения изображения, и иллюзия идеальна!

Я знаю, что логику этого трюка понять непросто. Не волнуйтесь, если вы не полностью понимаете это. Самое важное — понять структуру используемого кода и то, как его модифицировать, чтобы получить больше вариаций. Это то, что мы будем делать дальше!

Добавление дополнительных изображений

Мы создали сетку 3×3, чтобы объяснить основной трюк, но вы, наверное, догадались, что нам не нужно останавливаться на достигнутом. Мы можем сделать количество столбцов и строк переменными и добавить столько изображений, сколько захотим.

.gallery {
  --n: 3; /* number of rows*/
  --m: 4; /* number of columns */
  --s: 150px; /* control the size */
  --g: 10px;  /* control the gap */
  --f: 1.5;   /* control the scale factor */

  display: grid;
  gap: var(--g);
  width:  calc(var(--m)*var(--s) + (var(--m) - 1)*var(--g));
  height: calc(var(--n)*var(--s) + (var(--n) - 1)*var(--g));
  grid-template-columns: repeat(var(--m),auto);
}

У нас есть две новые переменные для количества строк и столбцов. Затем мы просто определяем ширину и высоту нашей сетки, используя их. То же самое для grid-template-columns который использует --m переменная. И, как и раньше, нам не нужно явно определять строки, поскольку функция автоматического размещения CSS Grid сделает всю работу за нас, независимо от того, сколько элементов изображения мы используем.

Почему не разные значения ширины и высоты? Мы можем это сделать:

.gallery {
  --n: 3; /* number of rows*/
  --m: 4; /* number of columns */
  --h: 120px; /* control the height */
  --w: 150px; /* control the width */
  --g: 10px;  /* control the gap */
  --f: 1.5;   /* control the scale factor */

  display: grid;
  gap: var(--g);
  width:  calc(var(--m)*var(--w) + (var(--m) - 1)*var(--g));
  height: calc(var(--n)*var(--h) + (var(--n) - 1)*var(--g));
  grid-template-columns: repeat(var(--m),auto);
}

.gallery img:hover{
  width:  calc(var(--w)*var(--f));
  height: calc(var(--h)*var(--f));
}

Мы заменяем --s с двумя переменными, одна для ширины, --w, и еще один для высоты, --h. Затем мы соответствующим образом настраиваем все остальное.

Итак, мы начали с сетки с фиксированным размером и количеством элементов, но затем создали новый набор переменных, чтобы получить любую желаемую конфигурацию. Все, что нам нужно сделать, это добавить столько изображений, сколько мы хотим, и соответствующим образом настроить переменные CSS. Комбинации безграничны!

А полноэкранная версия? Да, это тоже возможно. Все, что нам нужно, это знать, какие значения мы должны присвоить нашим переменным. Если мы хотим N ряды изображений, и мы хотим, чтобы наша сетка была полноэкранной, нам сначала нужно решить для высоты 100vh:

var(--n) * var(--h) + (var(--n) - 1) * var(--g) = 100vh

Та же логика для ширины, но с использованием vw вместо vh:

var(--m) * var(--w) + (var(--m) - 1) * var(--g) = 100vw

Делаем математику, чтобы получить:

--w: (100vw - (var(--m) - 1) * var(--g)) / var(--m)
--h: (100vh - (var(--n) - 1) * var(--g)) / var(--n)

Готово!

Это точно такой же HTML, но с некоторыми обновленными переменными, которые изменяют размер и поведение сетки.

Обратите внимание, что я опустил формулу, которую мы ранее установили на .gallery«s width и height и заменил их 100vw и 100vh, соответственно. Формула даст нам тот же результат, но, поскольку мы знаем, какое значение нам нужно, мы можем избавиться от всей этой дополнительной сложности.

Мы также можем упростить --h и --w удалив пробел из уравнения в пользу этого:

--h: calc(100vh / var(--n)); /* Viewport height divided by number of rows */
--w: calc(100vw / var(--m)); /* Viewport width divided by number of columns */

Это приведет к тому, что наведенное изображение увеличится немного больше, чем в предыдущем примере, но это не имеет большого значения, поскольку мы можем контролировать масштаб с помощью --f переменная, которую мы используем в качестве множителя.

А так как переменные используются в одном месте, мы можем упростить код, удалив их совсем:

Важно отметить, что эта оптимизация применяется только к полноэкранному примеру, а не к примерам, которые мы рассмотрели. Этот пример является частным случаем, когда мы можем сделать код легче, удалив часть сложной вычислительной работы, необходимой в других примерах.

На самом деле у нас есть все необходимое для создания популярного шаблона расширяющихся панелей:

Давайте копнем еще глубже

Вы заметили, что наш коэффициент масштабирования может быть меньше, чем 1? Мы можем определить размер наводимого изображения меньше, чем --h or --w но изображение становится больше при наведении.

Начальный размер ячейки сетки равен --w и --h, так почему же меньшие значения делают ячейку сетки больший? Не должна ли клетка получить меньше, или хотя бы сохранить свой первоначальный размер? И каков окончательный размер ячейки сетки?

Нам нужно углубиться в то, как алгоритм CSS Grid вычисляет размер ячеек сетки. И это включает в себя понимание CSS Grid по умолчанию растянуть выравнивание.

Вот пример для понимания логики.

В левой части демонстрации я определил два столбца с auto ширина. Получаем интуитивно понятный результат: два равных столбца (и две равные ячейки сетки). Но сетка, которую я установил в правой части демонстрации, где я обновляю выравнивание, используя place-content: start, кажется, ничего.

DevTools помогает показать нам, что на самом деле происходит в обоих случаях:

Масштабирование изображений в сетке PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.
Масштабирование изображений в макете сетки

Во второй сетке у нас есть два столбца, но их ширина равна нулю, поэтому мы получаем две ячейки сетки, свернутые в верхнем левом углу контейнера сетки. Это не ошибка, а логический результат выравнивания сетки. Когда мы измеряем столбец (или строку) с помощью auto, это означает, что его содержимое диктует его размер — но у нас есть пустой div без содержания, для которого можно было бы освободить место.

Но так как stretch является выравниванием по умолчанию, и у нас достаточно места внутри нашей сетки, браузер равномерно растянет обе ячейки сетки, чтобы покрыть всю эту область. Вот так сетка слева состоит из двух равных столбцов.

от спецификация:

Обратите внимание, что некоторые значения justify-content и align-content может привести к разнесению дорожек (space-around, space-between, space-evenly) или изменить размер (stretch).

Обратите внимание на ключевое слово «изменить размер». В последнем примере я использовал place-content что является сокращением для justify-content и align-content

И это зарыто где-то в алгоритм определения размера сетки спецификации:

Этот шаг расширяет дорожки, которые имеют автоматический функция максимального размера дорожки путем деления любого оставшегося положительного, определенный свободное пространство поровну среди них. Если свободное место неопределенный, Но сетка-контейнер имеет определенный мин-ширина/высота, используйте этот размер для расчета свободного места для этого шага.

«Ровно» объясняет, почему мы получаем одинаковые ячейки сетки, но это относится и к «свободному пространству», что очень важно.

Возьмем предыдущий пример и добавим содержимое в один из divs:

Мы добавили квадрат 50px изображение. Вот иллюстрация того, как каждая сетка в нашем примере реагирует на это изображение:

Масштабирование изображений в сетке PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.
Масштабирование изображений в макете сетки

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

Это математика, чтобы выяснить наше свободное пространство:

(grid width) - (gap) - (image width) = (free space)
200px - 5px - 50px = 145px 

Делим на два — количество столбцов — получаем ширину 72.5px для каждого столбца. Но мы добавляем размер изображения, 50px, в первый столбец, который оставляет нам один столбец в 122.5px а второй равен 72.5px.

Та же логика применима к нашей сетке изображений. Все изображения имеют размер, равный 0 (без содержимого), в то время как наведенное изображение влияет на размер, даже если оно просто 1px — сделать свою ячейку сетки больше остальных. По этой причине коэффициент масштабирования может быть любым значением больше, чем 0 даже десятичные дроби между 0 и 1.

Чтобы получить окончательную ширину ячеек сетки, мы делаем тот же расчет, чтобы получить следующее:

(container width) - (sum of all gaps) - (hovered image width) = (free space)

Ширина контейнера определяется:

var(--m)*var(--w) + (var(--m) - 1)*var(--g)

…и все промежутки равны:

(var(--m) - 1)*var(--g)

… и для зависшего изображения у нас есть:

var(--w)*var(--f)

Мы можем вычислить все это с помощью наших переменных:

var(--m)*var(--w) - var(--w)*var(--f) = var(--w)*(var(--m) - var(--f))

Количество столбцов определяется --m , поэтому мы делим это свободное пространство поровну, чтобы получить:

var(--w)*(var(--m) - var(--f))/var(--m)

… что дает нам размер ненаведенных изображений. Для наведенных изображений у нас есть это:

var(--w)*(var(--m) - var(--f))/var(--m) + var(--w)*var(--f)
var(--w)*((var(--m) - var(--f))/var(--m) + var(--f))

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

(var(--m) - var(--f))/var(--m) + var(--f) = 2

Итак, значение нашего масштабного множителя, --f, должно быть равно:

var(--m)/(var(--m) - 1)

Для трех столбцов будем иметь 3/2 = 1.5 и это коэффициент масштабирования, который я использовал в первой демонстрации этой статьи, потому что я хотел сделать изображение в два раза больше при наведении курсора!

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

.gallery {
  /* same as before */
   --fw: 1.5; /* controls the scale factor for the width */
   --fh: 1.2; /* controls the scale factor for the height */

  /* same as before */
}

.gallery img:hover{
  width:  calc(var(--w)*var(--fw));
  height: calc(var(--h)*var(--fh));
}

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

Подведение итогов

В моем Последняя статья, мы создали сложную сетку с помощью нескольких строк CSS, которые задействовали неявную сетку CSS Grid и функции автоматического размещения. В этой статье мы полагались на некоторые трюки с размером CSS Grid, чтобы создать причудливую сетку изображений, которые масштабируются при наведении и заставляют сетку соответствующим образом корректироваться. Все это с помощью упрощенного кода, который легко настроить с помощью переменных CSS!

В следующей статье мы поиграем с формами! Мы объединим сетку CSS с маской и clip-path, чтобы получить причудливую сетку изображений.

Отметка времени:

Больше от CSS хитрости