Створіть повторюваний гексагональний шаблон за допомогою CSS3


79

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

Ось ідея того, що я намагаюся створити:

введіть тут опис зображення

В основному, мені просто потрібен спосіб створити шестикутні фігури, а потім накласти текст / зображення поверх них. У мене поки що небагато коду, бо я не дуже впевнений, з чого почати. Проблема в тому, що я міг би просто використовувати <div>s у формі шестикутника, як показано на ( http://css-tricks.com/examples/ShapesOfCSS/ ), але тоді вони не підключалися. Я міг би використовувати повторюваний шестикутник, але тоді я б не міг вказати точне розташування тексту чи зображень, які мені потрібні, у конкретних фігурах. Дякуємо за будь-яку допомогу заздалегідь.


2
Є маски CSS, але підтримка жахлива: webkit.org/blog/181/css-masks
mddw

Для того ж самого шестикутника з використанням <img>тегу замість фонового зображення ви можете перевірити Сітку шестикутників з тегом <img> .
web-tiki

Я зробив sass-версію рішення ScottS, щоб швидко мати різні розміри. Перевірте тут codepen.io/mort3za/pen/wBabaB
Morteza Ziyae

Відповіді:


130

(Хоча відповідь Ана прийшла через кілька місяців після моєї, ймовірно, використовуючи мою як основу для "думки", той факт, що вона змогла придумати метод, використовуючи один сингл div, варто рекламувати, тому перевірте її відповідь теж - але зверніть увагу, що вміст у hex є більш обмеженим.)

Це було справді дивовижне питання. Дякую, що запитали. Найкраще те, що:

Ця скрипка доводить, що ви можете це зробити!

Оригінальна скрипка, використана (змінена в подальшому редагуванні на посилання для скрипки вище) - вона використовувала зображення imgur.com, які, здавалося б, не були дуже надійними при завантаженні, тому нова скрипка використовує photobucket.com ( дайте мені знати, чи є постійні проблеми із завантаженням зображень ). Я зберіг оригінальне посилання, оскільки код пояснення нижче відповідає цьому (є кілька відмінностей у новій скрипці background-sizeабо positionв ній).

Ідея прийшла мені в голову майже миттєво після прочитання вашого запитання, але на її реалізацію знадобився певний час. Спочатку я намагався отримати єдиний "шістнадцятковий" з одним divі просто псевдоелементами, але, як я міг сказати, не було можливості просто повернути background-image(що мені потрібно), тому мені довелося додати кілька додаткових divелементів, щоб отримати правильний / ліві сторони шестигранника, щоб я міг потім використовувати псевдоелементи як засіб background-imageобертання.

Я тестував у IE9, FF та Chrome. Теоретично будь-який браузер, що підтримує CSS3, в якому transformвін повинен працювати.

Перше основне оновлення (додане пояснення)

Зараз у мене є трохи часу, щоб опублікувати якесь пояснення коду, тому тут йдеться:

По-перше, шестикутники визначаються співвідношенням 30/60 градусів та тригонометрією, тож це будуть ключові кути. По-друге, ми починаємо з "рядка" для розміщення шістнадцяткової сітки. HTML визначається як (додаткові divелементи допомагають побудувати шістнадцяткову форму):

<div class="hexrow">
    <div>
        <span>First Hex Text</span>
        <div></div>
        <div></div>
    </div>
    <div>
        <span>Second Hex Text</span>
        <div></div>
        <div></div>
    </div>
    <div>
        <span>Third Hex Text</span>
        <div></div>
        <div></div>
    </div>
</div>

Ми збираємось використовувати його inline-blockдля шестикутника display, але ми не хочемо, щоб вони випадково перейшли до наступного рядка і зіпсували сітку, тому white-space: nowrapвирішує цю проблему. Цей marginрядок буде залежати від того, скільки місця ви хочете між шістнадцяткою, і можуть знадобитися деякі експерименти, щоб отримати те, що ви хочете.

.hexrow {
    white-space: nowrap;
    /*right/left margin set at (( width of child div x sin(30) ) / 2) 
    makes a fairly tight fit; 
    a 3px bottom seems to match*/
    margin: 0 25px 3px;
}

Використовуючи безпосередні .hexrowдочірні divелементи, які є лише елементами, ми формуємо основу для шестигранної форми. widthУправлятиме горизонтальним верхньою частиною гекса, то heightпоходить від цього числа , так як всі сторони дорівнює за тривалістю правильного шестикутника. Знову ж, запас буде залежати від інтервалів, але саме тут відбуватиметься "перекриття" окремих шестикутників, щоб зробити вигляд сітки. Це background-imageвизначається один раз, тут. Зсув, що залишився на ньому, повинен забезпечити принаймні додану ширину для лівої сторони шестигранника. Якщо припустити, що вам потрібен текст по центру, він text-alignобробляє горизонталь (звичайно), але той, line-heightщо відповідає height, збирається дозволити вертикальне центрування.

.hexrow > div {
    width: 100px;
    height: 173.2px; /* ( width x cos(30) ) x 2 */
    /* For margin:
    right/left = ( width x sin(30) ) makes no overlap
    right/left = (( width x sin(30) ) / 2) leaves a narrow separation
    */
    margin: 0 25px;
    position: relative;
    background-image: url(http://i.imgur.com/w5tV4.jpg);
    background-position: -50px 0; /* -left position -1 x width x sin(30) */
    background-repeat: no-repeat;
    color: #ffffff;
    text-align: center;
    line-height: 173.2px; /*equals height*/
    display: inline-block;
}

Кожне непарне число шістнадцяткового числа ми будемо зміщувати вниз по відношенню до "рядка" і кожне парне - вгору. Розрахунок зсуву (ширина x cos (30) / 2) також збігається з (висота / 4).

.hexrow > div:nth-child(odd) {
    top: 43.3px; /* ( width x cos(30) / 2 ) */
}

.hexrow > div:nth-child(even) {
    top: -44.8px; /* -1 x( ( width x cos(30) / 2) + (hexrow bottom margin / 2)) */
}

Ми використовуємо 2 дочірні divелементи для створення «крил» шестигранника. Вони розміром однакові з основним шестигранним прямокутником, а потім обертаються і штовхаються "нижче" основного шестигранника. Background-imageуспадковується таким чином, щоб зображення було однаковим (звичайно), оскільки зображення в "крилах" буде "вишикуватися" до зображення в основному прямокутнику. Псевдоелементи використовуються для генерації зображень, тому що їх потрібно "повернути" до горизонтального (оскільки ми повернули батьківський елемент divдля створення "крил").

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

.hexrow > div > div:first-of-type {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    z-index: -1;
    overflow: hidden;
    background-image: inherit;

    -ms-transform:rotate(60deg); /* IE 9 */
    -moz-transform:rotate(60deg); /* Firefox */
    -webkit-transform:rotate(60deg); /* Safari and Chrome */
    -o-transform:rotate(60deg); /* Opera */
    transform:rotate(60deg);
}

.hexrow > div > div:first-of-type:before {
    content: '';
    position: absolute;
    width: 200px; /* width of main + margin sizing */
    height: 100%;
    background-image: inherit;
    background-position: top left;
    background-repeat: no-repeat;
    bottom: 0;
    left: 0;
    z-index: 1;

    -ms-transform:rotate(-60deg) translate(-150px, 0); /* IE 9 */
    -moz-transform:rotate(-60deg) translate(-150px, 0); /* Firefox */
    -webkit-transform:rotate(-60deg) translate(-150px, 0); /* Safari and Chrome */
    -o-transform:rotate(-60deg) translate(-150px, 0); /* Opera */
    transform:rotate(-60deg) translate(-150px, 0);

    -ms-transform-origin: 0 0; /* IE 9 */
    -webkit-transform-origin: 0 0; /* Safari and Chrome */
    -moz-transform-origin: 0 0; /* Firefox */
    -o-transform-origin: 0 0; /* Opera */
    transform-origin: 0 0;
}

.hexrow > div > div:last-of-type {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    z-index: -2;
    overflow: hidden;
    background-image: inherit;

    -ms-transform:rotate(-60deg); /* IE 9 */
    -moz-transform:rotate(-60deg); /* Firefox */
    -webkit-transform:rotate(-60deg); /* Safari and Chrome */
    -o-transform:rotate(-60deg); /* Opera */
    transform:rotate(-60deg);
}

.hexrow > div > div:last-of-type:before {
    content: '';
    position: absolute;
    width: 200px; /* starting width + margin sizing */
    height: 100%;
    background-image: inherit;
    background-position: top left;
    background-repeat: no-repeat;
    bottom: 0;
    left: 0;
    z-index: 1;

    /*translate properties are initial width (100px) and half height (173.2 / 2 = 86.6) */
    -ms-transform:rotate(60deg) translate(100px, 86.6px); /* IE 9 */
    -moz-transform:rotate(60deg) translate(100px, 86.6px); /* Firefox */
    -webkit-transform:rotate(60deg) translate(100px, 86.6px); /* Safari and Chrome */
    -o-transform:rotate(60deg) translate(100px, 86.6px); /* Opera */
    transform:rotate(60deg) translate(100px, 86.6px);

    -ms-transform-origin: 100% 0; /* IE 9 */
    -webkit-transform-origin: 100% 0; /* Safari and Chrome */
    -moz-transform-origin: 100% 0; /* Firefox */
    -o-transform-origin: 100% 0; /* Opera */
    transform-origin: 100% 0;
}

Тут spanрозміщується ваш текст. Цей параметр line-heightскидається, щоб зробити рядки тексту нормальними, але vertical-align: middleпрацює, оскільки він line-heightбув більшим на батьківському. white-spaceСкидається , так що дозволяє обертати знову. Для лівого / правого поля можна встановити мінус, щоб текст міг перейти в "крила" шістнадцяткового тексту.

.hexrow > div > span {
    display: inline-block;
    margin: 0 -30px;
    line-height: 1.1;
    vertical-align: middle;
    white-space: normal;
}

Ви можете окремо націлити рядки та комірки в цих рядках, щоб змінити зображення, або spanпараметри тексту, або непрозорість, або розмістити більше зображення (щоб перемістити його у потрібне місце) тощо. Це те, що робиться для другого рядка.

.hexrow:nth-child(2) > div:nth-child(1) {
    background-image: url(http://i.imgur.com/7Un8Y.jpg);
}

.hexrow:nth-child(2) > div:nth-child(1) > span {
    /*change some other settings*/
    margin: 0 -20px;
    color: black;
    font-size: .8em;
    font-weight: bold;
}

.hexrow:nth-child(2) > div:nth-child(2) {
    background-image: url(http://i.imgur.com/jeSPg.jpg);
}

.hexrow:nth-child(2) > div:nth-child(3) {
    background-image: url(http://i.imgur.com/Jwmxm.jpg);
    /*you can shift a large background image, but it can get complicated
    best to keep the image as the total width (200px) and height (174px)
    that the hex would be.
    */
    background-position: -150px -120px;
    opacity: .3;
    color: black;
}

.hexrow:nth-child(2) > div:nth-child(3) > div:before {
    /*you can shift a large background image, but it can get complicated
    best to keep the image as the total width (200px) and height (174px)
    that the hex would be.
    */
    background-position: -100px -120px; /* the left shift is always less in the pseudo elements by the amount of the base shift */
}

.hexrow:nth-child(2) > div:nth-child(4) {
    background-image: url(http://i.imgur.com/90EkV.jpg);
    background-position: -350px -120px;
}

.hexrow:nth-child(2) > div:nth-child(4) > div:before {
    background-position: -300px -120px;
}

1
Дякуємо, що дали таку добре пояснену, ґрунтовну та геніальну відповідь, це чудово!
element119

@ScottS У мене виникла найдивніша проблема з його реалізацією. Я використовую Bootstrap інструментарій Twitter, і чому - то завжди здається , як це . Я зменшив проблему до div.container: макет стає заплутаним, коли шестикутник знаходиться в цьому контейнері div. Однак дивним є погляд на порівняння між кожним сценарієм: посилання та посилання . Я провів кілька тестів, але не можу зрозуміти, що заплутало шестикутники!
element119

@ Archio - По-перше, ви показуєте код для дочірнього рівня першого рівня шестигранного рядка, але проблема, ймовірно, стосується дочірнього рівня другого рівня, які генерують "крила" шістнадцяткового тексту, оскільки ця частина зображення відсутня тому я не можу налагодити). Проблема могла бути там (an overflow: hiddenзробить те, що ви покажете), але, схоже, це не так. Подивіться на вкладеність другого рівня divта його :beforeкод, оскільки, швидше за все, або divне обертається у перетворенні, або background-imageне успадковує і це, divі його :beforeпсевдоелемент.
ScottS

Я щойно перевірив - вони, здається, успадковують колір тла ( посилання ). Вони також обертаються, я бачу, що їх обертають у веб-інспекторі Chrome. Проблема в тому, що вони просто не відображаються, навіть якщо вони є display:block.
element119

Ах, здається, знайшов! Схоже, проблема була z-index. Зараз я його налаштовую, щоб переконатися, що все працює правильно.
element119

53

Насправді це можна зробити лише з одним елементом на шестикутник та псевдоелементами для фонового зображення та тексту.

демо

Базова структура HTML :

<div class='row'>
    <div class='hexagon'></div>
</div>
<div class='row'>
    <div class='hexagon content ribbon' data-content='This is a test!!! 
    9/10'></div><!--
    --><div class='hexagon content longtext' data-content='Some longer text here.
       Bla bla bla bla bla bla bla bla bla bla blaaaah...'></div>
</div>

Ви можете мати більше рядків, вам просто потрібно мати nшестикутники на непарних рядках і n+/-1шестикутники на парних рядках.

Відповідний CSS :

* { box-sizing: border-box; margin: 0; padding: 0; }
.row { margin: -18.5% 0; text-align: center; }
.row:first-child { margin-top: 7%; }
.hexagon {
    position: relative;
    display: inline-block;
    overflow: hidden;
    margin: 0 8.5%;
    padding: 16%;
    transform: rotate(30deg) skewY(30deg) scaleX(.866); /* .866 = sqrt(3)/2 */
}
.hexagon:before, .content:after {
    display: block;
    position: absolute;
    /* 86.6% = (sqrt(3)/2)*100% = .866*100% */
    top: 6.7%; right: 0; bottom: 6.7%; left: 0; /* 6.7% = (100% -86.6%)/2 */
    transform: scaleX(1.155) /* 1.155 = 2/sqrt(3) */ 
               skewY(-30deg) rotate(-30deg);
    background-color: rgba(30,144,255,.56);
    background-size: cover;
    content: '';
}
.content:after { content: attr(data-content); }
/* add background images to :before pseudo-elements */
.row:nth-child(n) .hexagon:nth-child(m):before {
    background-image: 
        url(background-image-mxn.jpg); 
}

5
Це справді заслуговує на більшу оцінку! Настільки стислий і простий, а демонстрація справді демонструє універсальність. Єдиним недоліком може бути те, що вміст зберігається в атрибуті, а не в самому елементі.
Thomas W

Ви можете помістити вміст у дочірній елемент :) Я лише хотів мінімізувати кількість HTML-елементів, необхідних тут. Але дочірній елемент із фактичним змістом можна легко використовувати замість псевдо.
Ана

2
Ви маєте рацію, в основному вимагає лише заміни .content:afterна .hexagon > *. Геніальний.
Thomas W

будь-які думки про те, як поля між шестикутниками можна елегантно змінити?
maxheld

як не дивно, якщо його розширити до цілої групи шестикутників, це стає неприємним на сафарі, як це питання
maxheld

2

Я дам просту демонстраційну версію того, як створити шестикутну форму.

.hex {
  width: 40px;
  height: 70px;
  margin: 20px;
  overflow: hidden;
}

.hex:before {
  content: "";
  transform: rotate(45deg);
  background: #f00;
  width: 50px;
  height: 50px;
  display: inline-block;
  margin: 10px -5px 10px -5px;
}
<div class="hex">
</div>



1

Ви можете створити повністю чутливу гексагональну сітку, використовуючи лише CSS. Ідея полягає в тому, щоб створити батьківську фігуру як маску, використовуючи переповнення CSS2.1: hidden, яке сумісне майже з усіма браузерами, навіть Internet Explorer 6.

Це напрочуд проста техніка, яка може бути використана для створення чутливої ​​сітки будь-яких форм, для вирішення проблеми потрібно лише продумати нестандартно.

У мене є велике покрокове керівництво щодо того, як зробити цю техніку тут: https://www.codesmite.com/article/how-to-create-pure-css-hexagonal-grids

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

Я також використав цю техніку у безкоштовному HTML-шаблоні, що включає зображення всередині шестикутників, які ви можете демонструвати та завантажувати тут: https://www.codesmite.com/freebie/hexa-free-responsive-portfolio-template


0

якщо ви в змозі реалізувати фокус у формах div, просто дайте кожному div a position:relative(спочатку потрібно було б розташувати їх усіх по одному, також встановивши topі left)


Чи можете ви навести приклад у JSFiddle? Хитрість у формах div насправді не працює, якщо мені потрібно заповнити шестикутник зображеннями та текстом.
element119

1
Так, ви зможете створювати лише однокольорові фігури: jsfiddle.net/Exceeder/cVqtW Не можна буде використовувати ці div в якості областей відсікання для фонових зображень або для формування тексту.
Alex Pakka,

-2

AFAIK, неможливо зробити це в чистому CSS. Найкращим варіантом було б використовувати відсікання маски для фонів, як пояснюється тут: http://www.cssbakery.com/2009/06/background-image.html (це буде працювати лише в тому випадку, якщо тло вашої сторінки однотонне або ви можете вмістити і розташуйте маску відповідно до фону сторінки.

Тоді ви можете використовувати csstextwrap, щоб вміститися в тексті: http://www.csstextwrap.com/examples.php

Була купа подібних питань щодо SO. Наприклад, будь-яким способом, щоб текст у div заповнював фігуру трикутника?


Алекс, просто хотів, щоб ти знав, що можна зробити в чистому CSS3 (див. Мою відповідь).
ScottS
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.