Сітка CSS і спеціальні фігури, частина 2 PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

CSS Grid and Custom Shapes, Частина 2

Добре, значить востаннє ми зареєструвалися, ми використовували CSS Grid і поєднували їх із CSS clip-path та mask техніки створення сіток химерних форм.

Ось лише одна з фантастичних сіток, які ми створили разом:

Готові до другого туру? Ми все ще працюємо з CSS Grid, clip-path та mask, але до кінця цієї статті ми розглянемо різні способи розташування зображень у сітці, включно з деякими ефектами радіального наведення, які створять автентичний інтерактивний досвід перегляду зображень.

І вгадайте що? Ми використовуємо та сама розмітка, яку ми використовували минулого разу. Ось ще раз:

<div class="gallery">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <!-- as many times as we want -->
</div>

Як і в попередній статті, нам потрібен тільки контейнер із зображеннями всередині. Нічого більше!

Сітка вкладених зображень

Минулого разу наші сітки були типовими сітками зображень. За винятком акуратних форм, якими ми їх замаскували, вони були досить стандартними симетричними сітками щодо того, як ми розташували зображення всередині.

Давайте спробуємо вкласти зображення в центр сітки:

Ми починаємо з встановлення сітки 2✕2 для чотирьох зображень:

.gallery {
  --s: 200px; /* controls the image size */
  --g: 10px; /* controls the gap between images */

  display: grid;
  gap: var(--g);
  grid-template-columns: repeat(2, auto);
}
.gallery > img {
  width: var(--s);
  aspect-ratio: 1;
  object-fit: cover;
}

Поки нічого складного. Наступним кроком буде зрізання кута наших зображень, щоб створити простір для вкладеного зображення. У мене вже є докладна стаття про як зрізати кути за допомогою clip-path та mask. Ви також можете використовувати мій онлайн генератор щоб отримати CSS для маскування кутів.

Тут нам потрібно вирізати кути під кутом, рівним 90deg. Ми можемо використовувати те саме конічно-градієнтна техніка з цієї статті, щоб зробити це:

.gallery > img {
   mask: conic-gradient(from var(--_a), #0000 90deg, #000 0);
}
.gallery > img:nth-child(1) { --_a: 90deg; }
.gallery > img:nth-child(2) { --_a: 180deg; }
.gallery > img:nth-child(3) { --_a: 0deg; }
.gallery > img:nth-child(4) { --_a:-90deg; }

Ми могли б використати clip-path метод зрізання кутів із тієї самої статті, але тут більше підходить маскування за допомогою градієнтів, оскільки ми маємо однакову конфігурацію для всіх зображень — все, що нам потрібно, це обертання (визначене за допомогою змінної --_a) отримати ефект, тому ми маскуємо з внутрішніх, а не зовнішніх країв.

CSS Grid and Custom Shapes, Частина 2

Тепер ми можемо розмістити вкладене зображення всередині замаскованого простору. По-перше, давайте переконаємося, що у нас є п’ятий елемент зображення в HTML:

<div class="gallery">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
</div>

Ми будемо покладатися на старе добре абсолютне позиціонування, щоб розмістити його там:

.gallery > img:nth-child(5) {
  position: absolute;
  inset: calc(50% - .5*var(--s));
  clip-path: inset(calc(var(--g) / 4));
}

Команда inset властивість дозволяє нам розмістити зображення в центрі за допомогою єдиного оголошення. Ми знаємо розмір зображення (визначається за допомогою змінної --s), і ми знаємо, що розмір контейнера дорівнює 100%. Ми трохи обчислюємо, і відстань від кожного краю має дорівнювати (100% - var(--s))/2.

Діаграма ширини, необхідної для завершення конструкції.
CSS Grid and Custom Shapes, Частина 2

Вам може бути цікаво, чому ми використовуємо clip-path взагалі тут. Ми використовуємо його разом із вкладеним зображенням, щоб мати послідовний проміжок. Якби ми його видалили, ви б помітили, що у нас немає однакового проміжку між усіма зображеннями. Таким чином, ми трохи вирізаємо п’яте зображення, щоб отримати правильний відстань навколо нього.

Знову повний код:

.gallery {
  --s: 200px; /* controls the image size */
  --g: 10px;  /* controls the gap between images */
  
  display: grid;
  gap: var(--g);
  grid-template-columns: repeat(2, auto);
  position: relative;
}

.gallery > img {
  width: var(--s);
  aspect-ratio: 1;
  object-fit: cover;
  mask: conic-gradient(from var(--_a), #0000 90deg, #000 0);
}

.gallery > img:nth-child(1) {--_a: 90deg}
.gallery > img:nth-child(2) {--_a:180deg}
.gallery > img:nth-child(3) {--_a:  0deg}
.gallery > img:nth-child(4) {--_a:-90deg}
.gallery > img:nth-child(5) {
  position: absolute;
  inset: calc(50% - .5*var(--s));
  clip-path: inset(calc(var(--g) / 4));
}

Тепер багато хто з вас також може запитати: навіщо всі ці складні речі, коли ми можемо розмістити останнє зображення вгорі та додати до нього рамку? Це сховало б зображення під вкладеним зображенням без маски, вірно?

Це правда, і ми отримаємо наступне:

Немає maskВ clip-path. Так, код простий для розуміння, але є невеликий недолік: колір рамки має бути таким самим, як і основний фон, щоб зробити ілюзію ідеальною. Цього маленького недоліку мені достатньо, щоб зробити код складнішим в обмін на реальну прозорість незалежно від фону. Я не кажу, що підхід до кордону поганий чи неправильний. Я б рекомендував це в більшості випадків, коли передісторія відома. Але ми тут, щоб досліджувати нові речі і, що найважливіше, створювати компоненти, які не залежать від середовища.

Цього разу давайте спробуємо іншу форму:

Цього разу ми зробили вкладене зображення колом замість квадрата. Це легке завдання border-radius Але нам потрібно використовувати a круговий виріз для інших зображень. Однак цього разу ми будемо спиратися на a radial-gradient() замість а conic-gradient() щоб отримати гарний округлий вигляд.

.gallery > img {
  mask: 
    radial-gradient(farthest-side at var(--_a),
      #0000 calc(50% + var(--g)/2), #000 calc(51% + var(--g)/2));
}
.gallery > img:nth-child(1) { --_a: calc(100% + var(--g)/2) calc(100% + var(--g)/2); }
.gallery > img:nth-child(2) { --_a: calc(0%   - var(--g)/2) calc(100% + var(--g)/2); }
.gallery > img:nth-child(3) { --_a: calc(100% + var(--g)/2) calc(0%   - var(--g)/2); }
.gallery > img:nth-child(4) { --_a: calc(0%   - var(--g)/2) calc(0%   - var(--g)/2); }

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

Діаграма, що показує центральні значення для кожного квадранта сітки.
CSS Grid and Custom Shapes, Частина 2

На малюнку вище показано центральну точку кожного кола. Тим не менш, у реальному коді ви помітите, що я також враховую проміжок, щоб переконатися, що всі точки знаходяться в одній позиції (у центрі сітки), щоб отримати безперервне коло, якщо ми їх об’єднаємо.

Тепер, коли у нас є наш макет, давайте поговоримо про ефект наведення. Якщо ви не помітили, крутий ефект наведення збільшує розмір вкладеного зображення та відповідно коригує все інше. Збільшення розміру є відносно легким завданням, але оновлення градієнта є більш складним, оскільки за замовчуванням градієнти не можна анімувати. Щоб подолати це, я буду використовувати a font-size хак, щоб мати можливість анімувати радіальний градієнт.

Якщо ви перевірите код градієнта, ви побачите, що я додаю 1em:

mask: 
    radial-gradient(farthest-side at var(--_a),
      #0000 calc(50% + var(--g)/2 + 1em), #000 calc(51% + var(--g)/2 + 1em));

Відомо, що em одиниці відносно батьківського елемента font-size, тому зміна font-size в .gallery також змінить обчислене em значення — це трюк, який ми використовуємо. Ми анімуємо font-size від значення 0 до заданого значення, і, як наслідок, градієнт анімується, роблячи вирізану частину більшою відповідно до розміру вкладеного зображення, яке стає більшим.

Ось код, який висвітлює частини, задіяні в ефекті наведення:

.gallery {
  --s: 200px; /* controls the image size */
  --g: 10px; /* controls the gaps between images */

  font-size: 0; /* initially we have 1em = 0 */
  transition: .5s;
}
/* we increase the cut-out by 1em */
.gallery > img {
  mask: 
    radial-gradient(farthest-side at var(--_a),
      #0000 calc(50% + var(--g)/2 + 1em), #000 calc(51% + var(--g)/2 + 1em));
}
/* we increase the size by 2em */
.gallery > img:nth-child(5) {
  width: calc(var(--s) + 2em);
}
/* on hover 1em = S/5 */
.gallery:hover {
  font-size: calc(var(--s) / 5);
}

Команда font-size трюк корисний, якщо ми хочемо анімувати градієнти або інші властивості, які не можна анімувати. Спеціальні властивості, визначені за допомогою @property, можуть вирішити таку проблему, але підтримка цього на момент написання статті все ще бракує.

Я виявив font-size трюк від @SelenIT2 намагаючись вирішити виклик у Twitter.

Інша форма? Ходімо!

Цього разу ми обрізали вкладене зображення у форму ромба. Я дозволю вам розібрати код як вправу, щоб зрозуміти, як ми сюди потрапили. Ви помітите, що структура така ж, як і в наших прикладах. Єдина відмінність полягає в тому, як ми використовуємо градієнт для створення форми. Копайте та вчіться!

Кругова сітка зображень

Ми можемо поєднати те, що ми дізналися тут і в попередніх статтях, щоб створити ще більш захоплюючу сітку зображень. Цього разу давайте зробимо всі зображення в нашій сітці круглими та, навівши курсор, розгорнемо зображення, щоб відкрити все, оскільки воно покриває решту фотографій.

У структурі сітки HTML і CSS немає нічого нового, тому давайте пропустимо цю частину і зосередимося на круглій формі та ефекті наведення, який нам потрібен.

Ми збираємось використовувати clip-path і її circle() функція — ви здогадалися! — вирізати коло із зображень.

Відображення двох станів зображення, природного стану ліворуч і стану наведення курсора праворуч, включно зі значеннями траєкторії кліпу для їх створення.
CSS Grid and Custom Shapes, Частина 2

Цей малюнок ілюструє clip-path використовувався для першого зображення. Ліва сторона показує початковий стан зображення, а права – наведений стан. Ви можете використовувати це онлайн-інструмент грати та візуалізувати clip-path значень.

Для інших зображень ми можемо оновити центр кола (70% 70%), щоб отримати такий код:

.gallery > img:hover {
  --_c: 50%; /* same as "50% at 50% 50%" */
}
.gallery > img:nth-child(1) {
  clip-path: circle(var(--_c, 55% at 70% 70%));
}
.gallery > img:nth-child(2) {
  clip-path: circle(var(--_c, 55% at 30% 70%));
}
.gallery > img:nth-child(3) {
  clip-path: circle(var(--_c, 55% at 70% 30%));
}
.gallery > img:nth-child(4) {
  clip-path: circle(var(--_c, 55% at 30% 30%));
}

Зверніть увагу, як ми визначаємо clip-path значення як запасний всередині var(). Цей спосіб дозволяє нам легше оновлювати значення під час наведення курсора, встановлюючи значення --_c змінна. При використанні circle(), положення центральної точки за замовчуванням 50% 50%, тому ми можемо опустити це для більш стислого коду. Тому ви бачите, що ми тільки встановлюємо 50% замість 50% at 50% 50%.

Потім ми збільшуємо розмір нашого зображення при наведенні до загального розміру сітки, щоб ми могли покрити інші зображення. Ми також забезпечуємо z-index має вище значення на наведеному зображенні, тому воно є верхнім у нашому укладання контексту.

.gallery {
  --s: 200px; /* controls the image size */
  --g: 8px;   /* controls the gap between images */

  display: grid;
  grid: auto-flow var(--s) / repeat(2, var(--s));
  gap: var(--g);
}

.gallery > img {
  width: 100%; 
  aspect-ratio: 1;
  cursor: pointer;
  z-index: 0;
  transition: .25s, z-index 0s .25s;
}
.gallery > img:hover {
  --_c: 50%; /* change the center point on hover */
  width: calc(200% + var(--g));
  z-index: 1;
  transition: .4s, z-index 0s;
}

.gallery > img:nth-child(1){
  clip-path: circle(var(--_c, 55% at 70% 70%));
  place-self: start;
}
.gallery > img:nth-child(2){
  clip-path: circle(var(--_c, 55% at 30% 70%));
  place-self: start end;
}
.gallery > img:nth-child(3){
  clip-path: circle(var(--_c, 55% at 70% 30%));
  place-self: end start;
}
.gallery > img:nth-child(4){
  clip-path: circle(var(--_c, 55% at 30% 30%));
  place-self: end;
}

Що відбувається з place-self власність? Навіщо це нам і чому кожне зображення має певну цінність?

Ви пам’ятаєте проблему, яку ми мали в попередній статті, коли створення сітки з частин пазла? Ми збільшили розмір зображень, щоб створити переповнення, але переповнення деяких зображень було неправильним. Ми виправили їх за допомогою place-self власність

Та сама проблема тут. Ми збільшуємо розмір зображень, щоб кожне з них переповнювало клітинки сітки. Але якщо ми нічого не зробимо, усі вони переповнять праву та нижню сторони сітки. Нам потрібно:

  1. перше зображення, яке виходить за нижній правий край (поведінка за замовчуванням),
  2. друге зображення виходить за нижній лівий край,
  3. третє зображення переповнює верхній правий край і
  4. четверте зображення виходить за верхній лівий край.

Щоб отримати це, нам потрібно правильно розмістити кожне зображення за допомогою place-self власність

Діаграма, що показує значення властивостей place-self для кожного квадранта сітки.
CSS Grid and Custom Shapes, Частина 2

Якщо ви не знайомі з place-self, це скорочення для justify-self та align-self розмістити елемент горизонтально і вертикально. Коли воно приймає одне значення, обидва вирівнювання використовують те саме значення.

Розгортання панелей зображень

У попередній статті, я створив класний ефект масштабування, який застосовується до сітки зображень, де ми можемо керувати всім: кількістю рядків, кількістю стовпців, розмірами, масштабним коефіцієнтом тощо.

Окремим випадком були класичні панелі, що розширюються, де ми маємо лише один ряд і контейнер на всю ширину.

Ми візьмемо цей приклад і поєднаємо його з формами!

Перш ніж продовжити, я настійно рекомендую прочитати мій інша стаття щоб зрозуміти, як працюють трюки, про які ми збираємось розповісти. Перевірте це, і ми продовжимо тут, щоб зосередитися на створенні форм панелей.

По-перше, давайте почнемо зі спрощення коду та видалення деяких змінних

Нам потрібен лише один рядок, а кількість стовпців слід регулювати залежно від кількості зображень. Це означає, що нам більше не потрібні змінні для кількості рядків (--n) та стовпці (--m ), але нам потрібно використовувати grid-auto-flow: column, що дозволяє сітці автоматично генерувати стовпці, коли ми додаємо нові зображення. Ми розглянемо фіксовану висоту для нашого контейнера; за замовчуванням він буде на всю ширину.

Давайте обріжемо зображення в похилу форму:

Знімок голови спокійного рудого вовка, який дивиться вниз, із накладеними вершинами, що показують точки властивостей траєкторії відсікання.
clip-path: polygon(S 0%, 100% 0%, (100% - S) 100%, 0% 100%);

Знову ж таки, кожне зображення міститься у своїй клітинці сітки, тому між зображеннями більше місця, ніж нам хотілося б:

Шестипанельна сітка з похилими зображеннями різних диких тварин із лініями сітки та пропусками.
CSS Grid and Custom Shapes, Частина 2

Нам потрібно збільшити ширину зображень, щоб створити перекриття. Замінюємо min-width: 100% з min-width: calc(100% + var(--s)), Де --s це нова змінна, яка керує формою.

Тепер нам потрібно виправити перше й останнє зображення, щоб вони ніби витікали зі сторінки без прогалин. Іншими словами, ми можемо видалити нахил з лівого боку першого зображення та нахил з правого боку останнього зображення. Нам потрібна нова clip-path спеціально для цих двох зображень.

Нам також потрібно виправити перелив. За замовчуванням усі зображення переливаються з обох боків, але для першого нам потрібне переповнення з правого боку, а для останнього зображення – зліва.

.gallery > img:first-child {
  min-width: calc(100% + var(--s)/2);
  place-self: start;
  clip-path: polygon(0 0,100% 0,calc(100% - var(--s)) 100%,0 100%);
}
.gallery > img:last-child {
  min-width: calc(100% + var(--s)/2);
  place-self: end;
  clip-path: polygon(var(--s) 0,100% 0,100% 100%,0 100%);
}

Кінцевим результатом є гарна розширювана панель похилих зображень!

Ми можемо додати скільки завгодно зображень, і сітка налаштується автоматично. Крім того, нам потрібно контролювати лише одне значення, щоб контролювати форму!

Ми могли б створити такий самий макет за допомогою flexbox, оскільки ми маємо справу з одним рядом елементів. Ось моя реалізація.

Звичайно, похилі зображення — це круто, але як щодо зигзагоподібного візерунка? Я вже дражнив цього кінець останньої статті.

Усе, що я тут роблю, це заміна clip-path з mask… і вгадайте що? У мене вже є докладна стаття про створення зигзагоподібної форми — не кажучи вже про онлайн генератор, щоб отримати код. Бачиш, як усе поєднується?

Найскладніша частина тут полягає в тому, щоб переконатися, що зигзаги ідеально вирівняні, а для цього нам потрібно додати зсув для кожного :nth-child(odd) елемент зображення.

.gallery > img {
  mask: 
    conic-gradient(from -135deg at right, #0000, #000 1deg 89deg, #0000 90deg) 
      100% calc(50% + var(--_p, 0%))/51% calc(2*var(--s)) repeat-y,
    conic-gradient(from   45deg at left,  #0000, #000 1deg 89deg, #0000 90deg) 
      0%   calc(50% + var(--_p, 0%))/51% calc(2*var(--s)) repeat-y;
}
/* we add an offset to the odd elements */
.gallery > img:nth-child(odd) {
  --_p: var(--s);
}
.gallery > img:first-child {
  mask: 
    conic-gradient(from -135deg at right, #0000, #000 1deg 89deg, #0000 90deg) 
      0 calc(50% + var(--_p, 0%))/100% calc(2*var(--s));
}
.gallery > img:last-child {
  mask: 
    conic-gradient(from 45deg at left, #0000, #000 1deg 89deg, #0000 90deg) 
      0 calc(50% + var(--_p, 0%)) /100% calc(2*var(--s));
}

Зверніть увагу на використання --_p змінна, яка повертатиметься до 0% але дорівнюватиме --_s для дивних зображень.

Ось демо, яке ілюструє проблему. Наведіть курсор, щоб побачити, як визначається зміщення --_p — фіксує центр.

Крім того, зверніть увагу на те, що ми використовуємо різні маски для першого та останнього зображень, як у попередньому прикладі. Нам потрібен лише зигзаг на правій стороні першого зображення та лівій стороні останнього зображення.

А чому б не закруглені боки? Давайте зробимо це!

Я знаю, що код може виглядати страшним і важким для розуміння, але все, що відбувається, це комбінація різних прийомів, про які ми розповідали в цій та інших статтях, якими я вже ділився. У цьому випадку я використовую ту саму структуру коду, що й зигзагоподібні та похилі форми. Порівняйте це з цими прикладами, і ви не побачите різниці! Це ті самі трюки моя попередня стаття про ефект масштабування. Тоді я використовую свій інше письмо та мій онлайн генератор щоб отримати код для маски, яка створює ці округлі форми.

Якщо ви пам’ятаєте, що ми робили для зигзагу, ми використовували однакову маску для всіх зображень, але потім довелося додати зсув до непарних зображень, щоб створити ідеальне перекриття. У цьому випадку нам потрібна інша маска для зображень з непарними номерами.

Перша маска:

mask: 
  linear-gradient(-90deg,#0000 calc(2*var(--s)),#000 0) var(--s),
  radial-gradient(var(--s),#000 98%,#0000) 50% / calc(2*var(--s)) calc(1.8*var(--s)) space repeat;
Сітка CSS і спеціальні фігури, частина 2 PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Другий:

mask:
  radial-gradient(calc(var(--s) + var(--g)) at calc(var(--s) + var(--g)) 50%,#0000 98% ,#000) 
  calc(50% - var(--s) - var(--g)) / 100% calc(1.8*var(--s))
Сітка CSS і спеціальні фігури, частина 2 PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Єдине, що я зробив тут, це оновити другу маску, щоб включити змінну проміжку (--g), щоб створити простір між зображеннями.

Останнім штрихом є закріплення першого і останнього зображення. Як і всі попередні приклади, для першого зображення потрібен прямий лівий край, а для останнього – прямий правий край.

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

.gallery > img:first-child {
  mask: 
    radial-gradient(calc(var(--s) + var(--g)) at right, #0000 98%, #000) 50% / 100% calc(1.8 * var(--s));
}
Знімок голови бурого ведмедя з хвилястим візерунком для правого краю.
CSS Grid and Custom Shapes, Частина 2

Для останнього зображення це залежить від кількості елементів, тому має значення, чи є цей елемент :nth-child(odd) or :nth-child(even).

Повна сітка фотографій диких тварин з усіма правильними межами та проміжками між зображеннями.
CSS Grid and Custom Shapes, Частина 2
.gallery > img:last-child:nth-child(even) {
  mask: 
    linear-gradient(to right,#0000 var(--s),#000 0),
    radial-gradient(var(--s),#000 98%,#0000) left / calc(2*var(--s)) calc(1.8*var(--s)) repeat-y
}
Однорядкова сітка з трьох фотографій диких тварин із хвилястими рамками, де останнє зображення є елементом з непарним номером.
CSS Grid and Custom Shapes, Частина 2
.gallery > img:last-child:nth-child(odd) {
  mask: 
    radial-gradient(calc(var(--s) + var(--g)) at left,#0000 98%,#000) 50% / 100% calc(1.8*var(--s))
}

Це все! Три різні макети, але щоразу однакові прийоми CSS:

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

А ось велика демонстрація з усіма ними разом. Все, що вам потрібно, це додати клас, щоб активувати макет, який ви хочете бачити.

А ось той із реалізацією Flexbox

Підводячи підсумок

Ой, ми закінчили! Я знаю, що між цією та попередньою статтями є багато трюків і прикладів CSS, не кажучи вже про всі інші трюки, на які я посилався тут з інших статей, які я написав. Мені знадобився час, щоб зібрати все докупи, а ви не повинні розуміти все відразу. Одне прочитання дасть вам хороший огляд усіх макетів, але вам, можливо, доведеться прочитати статтю більше одного разу та зосередитися на кожному прикладі, щоб зрозуміти всі хитрощі.

Ви помітили, що ми взагалі не торкалися HTML, окрім, можливо, кількості зображень у розмітці? Усі створені нами макети мають однаковий HTML-код, який є не чим іншим, як списком зображень.

Перш ніж закінчити, я залишу вас останнім прикладом. Це «супроти» між двома персонажами аніме з крутим ефектом наведення.

Що з вами? Чи можете ви створити щось на основі того, що ви навчилися? Це не обов’язково складне — уявіть щось круте чи смішне, як я зробив у тому матчі аніме. Це може бути гарною вправою для вас, і ми можемо закінчити чудовою колекцією в розділі коментарів.

Часова мітка:

Більше від CSS-хитрощі