web-dev-qa-db-fra.com

Générer un motif hexagonal répété avec CSS3

Donc, je dois faire un motif hexagonal répété, en utilisant CSS. Si des images sont nécessaires, je peux y aller, mais je préférerais simplement utiliser CSS si possible.

Voici une idée de ce que j'essaie de créer:

enter image description here

Fondamentalement, j'ai juste besoin d'un moyen de créer les formes hexagonales, puis de superposer du texte/des images dessus. Je n'ai pas encore beaucoup de code, car je ne sais pas trop par où commencer. Le problème est que je pourrais simplement utiliser <div>s sous la forme d'un hexagone comme indiqué dans ( http://css-tricks.com/examples/ShapesOfCSS/ ), mais ils ne se connecteraient pas. Je pourrais utiliser un motif hexagonal répétitif, mais je ne pourrais pas spécifier l'emplacement exact du texte ou des images dont j'ai besoin dans des formes spécifiques. Merci d'avance pour toute aide.

78
element119

(Bien que la réponse d’Ana apparaisse plusieurs mois après la mienne, utilisant probablement la mienne comme base pour "penser à", le fait qu’elle ait été en mesure de proposer une méthode utilisant un seul div vaut la peine d’être promue, donc consultez-la répondez trop - mais notez que le contenu de l'hex est plus limité.)

C'était une question vraiment incroyable. Merci de le demander. La grande chose est le fait que:

Ce Fiddle prouve que vous pouvez le faire!

Original Fiddle utilisé (modifié ultérieurement pour modifier le lien ci-dessus) - il utilisait des images imgur.com, qui ne semblaient pas très fiables au moment du chargement. Le nouveau violon utilise donc photobucket.com (laissez-moi savoir s'il y a des problèmes de chargement d'image persistants} _). J'ai conservé le lien d'origine car le code d'explication ci-dessous va avec (il y a quelques différences entre background-size et position au nouveau violon).

L'idée m'est venue presque instantanément après avoir lu votre question, mais a pris un certain temps à mettre en œuvre. À l’origine, j’ai essayé d’obtenir un seul "hex" avec un seul div et juste des pseudo-éléments, mais, autant que je sache, il n’existait aucun moyen de faire pivoter le background-image (ce dont j'avais besoin), aussi j’ai dû ajouter des éléments div supplémentaires à obtenir les côtés droit/gauche de l'hex, de sorte que je puisse ensuite utiliser les pseudo-éléments comme moyen de rotation background-image.

J'ai testé dans IE9, FF et Chrome. Théoriquement, tout navigateur prenant en charge CSS3 transform devrait fonctionner.

Première mise à jour principale (ajout d'une explication)

J'ai un peu de temps maintenant pour poster une explication de code, alors voici:

Premièrement, les hexagones sont définis par des relations à 30/60 degrés et une trigonométrie, ce sont donc les angles clés impliqués. Deuxièmement, nous commençons par une "ligne" dans laquelle la grille hexagonale doit résider. Le code HTML est défini comme suit (les éléments supplémentaires div aident à construire l'hex):

<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>

Nous allons utiliser inline-block pour l'hexagone display, mais nous ne voulons pas qu'ils retournent accidentellement à la ligne suivante et gâchent la grille, donc white-space: nowrap résout ce problème. Le margin sur cette ligne dépendra de l'espace que vous voulez entre les hexs, et des expériences pourront être nécessaires pour obtenir ce que vous voulez.

.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;
}

En utilisant les enfants immédiats du .hexrow qui ne sont que des éléments div, nous formons la base de la forme hexadécimale. width dirigera l’horizontal du sommet de l’hex, le height est dérivé de ce nombre puisque tous les côtés ont la même longueur sur un hexagone régulier. Encore une fois, la marge dépendra de l'espacement, mais c'est ici que le "chevauchement" des hexagones individuels se produira pour donner l'apparence de la grille. Le background-image est défini une fois, ici. Le décalage à gauche consiste à accepter au moins la largeur ajoutée pour le côté gauche de l'hex. En supposant que vous souhaitiez un texte centré, le text-align gère l’horizontale (bien sûr), mais le line-height correspondant au height permet un centrage vertical.

.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;
}

Chaque impair nombre hexadécimal que nous allons décaler par rapport à la "rangée" et chaque pair incrémenter. Le calcul du décalage (largeur x cos (30)/2) est également identique à celui (hauteur/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)) */
}

Nous utilisons 2 éléments div d'enfants pour créer les "ailes" de l'hex. Leur taille est identique à celle du rectangle principal, puis ils sont pivotés et poussés "sous" l’hex principal. Background-image est hérité de sorte que l'image soit la même (bien sûr), car l'image dans les "ailes" va être "alignée" sur celle du rectangle principal. Les pseudo-éléments sont utilisés pour générer les images, car elles doivent être "rerotées" pour revenir à l'horizontale (puisque nous avons fait pivoter le parent div pour créer les "ailes").

Le :before du premier traduira par son arrière-plan la largeur du montant négatif égale à la partie principale de l'hex plus le décalage d'origine de l'arrière-plan de l'hex principal. Le :before du second changera le point d'origine de la translation et décalera la largeur principale sur l'axe des x et la moitié de la hauteur sur l'axe des y.

.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;
}

Ce span abrite votre texte. Le line-height est réinitialisé pour rendre les lignes de texte normales, mais le vertical-align: middle fonctionne puisque le line-height était plus grand sur le parent. Le white-space est réinitialisé afin de permettre un nouveau wrapping. La marge gauche/droite peut être définie sur négative pour permettre au texte d'entrer dans les "ailes" de l'hex.

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

Vous pouvez individualiser des lignes et des cellules cibles dans ces lignes pour modifier les images, les paramètres de texte span, l'opacité ou une image plus grande (pour la déplacer à l'emplacement souhaité), etc. C'est ce que font les actions suivantes pour la deuxième ligne .

.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;
}
130
ScottS

Cela peut être fait avec un seul élément par hexagone et des pseudo-éléments pour l'image de fond et le texte.

démo

Structure de base 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>

Vous pouvez avoir plus de lignes, il vous suffit d’avoir des hexagones n sur des lignes impaires et des hexagones n+/-1 sur des lignes paires.

Pertinent 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); 
}
52
Ana

Je vais vous présenter une démonstration simple de la création d’une forme hexagonale.

.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>

2
Starx

Voici une autre approche utilisant COMPASS/SCSS, qui permet de définir facilement la taille et la disposition des hexagones:

http://codepen.io/interdruper/pen/GrBEk

1
Interdruper

si vous êtes capable de mettre en œuvre l’astuce des formes div, donnez simplement à chaque div un position:relative (vous devez d’abord les positionner un par un au début, en définissant également top et left)

0
RozzA

Vous pouvez créer une grille hexagonale entièrement réactive en utilisant uniquement CSS . L'idée est de créer une forme parent sous forme de masque avec CSS2.1 overflow: hidden compatible avec presque tous les navigateurs, même Internet Explorer 6.

C'est une technique étonnamment simple qui peut être utilisée pour créer une grille réactive de toutes sortes de formes. Il suffit simplement de sortir des sentiers battus pour résoudre le problème.

J'ai un guide détaillé étape par étape sur la façon de faire cette technique ici: https://www.codesmite.com/article/how-to-create-pure-cure-css-hexagonal-grids

C’est le meilleur moyen que j’ai trouvé jusqu’à présent, qui ne nécessite aucun javascript et qui est à la fois fluide et réactif.

J'ai également utilisé cette technique dans un modèle HTML gratuit contenant des images à l'intérieur des hexagones que vous pouvez télécharger et télécharger ici: https://www.codesmite.com/freebie/hexa-free-responsive-portfolio-template

0
Ash