Generieren Sie mit CSS3 sich wiederholende hexagonale Muster

79

Also muss ich mit CSS ein sich wiederholendes hexagonales Muster erstellen. Wenn Bilder benötigt werden, kann ich dorthin gehen, aber ich würde es vorziehen, wenn möglich nur CSS zu verwenden.

Hier ist eine Vorstellung davon, was ich zu erstellen versuche:

Geben Sie hier die Bildbeschreibung ein

Grundsätzlich brauche ich nur eine Möglichkeit, die sechseckigen Formen zu erstellen und dann Text / Bilder darüber zu legen. Ich habe noch nicht viel Code, weil ich nicht wirklich sicher bin, wo ich anfangen soll. Das Problem ist, ich könnte nur <div>s in Form eines Sechsecks verwenden, wie in ( http://css-tricks.com/examples/ShapesOfCSS/ ) gezeigt, aber dann würden sie keine Verbindung herstellen. Ich könnte ein sich wiederholendes Sechseckmuster verwenden, aber dann könnte ich die genaue Position des Textes oder der Bilder, die ich in bestimmten Formen benötige, nicht angeben. Vielen Dank für jede Hilfe im Voraus.

element119
quelle
2
Es gibt CSS-Masken, aber die Unterstützung ist schrecklich: webkit.org/blog/181/css-masks
mddw
Für dasselbe Sechseckmuster, das das <img>Tag anstelle eines Hintergrundbilds verwendet, können Sie das Sechseckraster mit dem Tag <img> überprüfen .
Web-Tiki
Ich habe eine Sass-Version der ScottS-Lösung erstellt, um schnell verschiedene Größen zu haben. Überprüfen Sie es hier codepen.io/mort3za/pen/wBabaB
Morteza Ziyae

Antworten:

130

(Obwohl Anas Antwort Monate nach meiner kam und wahrscheinlich meine als Grundlage zum "Nachdenken" verwendete, divlohnt es sich , die Tatsache zu fördern, dass sie eine Methode mit einer einzigen entwickeln konnte. Schauen Sie sich also auch ihre Antwort an - aber Beachten Sie, dass der Inhalt im Hex eingeschränkter ist.)

Dies war eine wirklich erstaunliche Frage. Danke, dass Sie es gefragt haben. Das Tolle ist die Tatsache, dass:

Diese Geige beweist, dass Sie es schaffen können!

Ursprüngliche Geige verwendet (in der späteren Bearbeitung geändert, um den obigen Geigen-Link zu verwenden) - es wurden Bilder von imgur.com verwendet, die beim Laden nicht sehr zuverlässig zu sein schienen, daher verwendet die neue Geige photobucket.com ( lassen Sie mich wissen, wenn es dauerhafte gibt) Probleme beim Laden von Bildern ). Ich habe den ursprünglichen Link beibehalten, da der unten stehende Erklärungscode dazu gehört (es gibt einige Unterschiede in background-sizeoder positionzur neuen Geige).

Die Idee kam mir fast sofort nach dem Lesen Ihrer Frage, aber die Umsetzung dauerte einige Zeit. Ich habe ursprünglich versucht, ein einzelnes "Hex" mit einem einzelnen divund nur Pseudoelementen zu erhalten, aber wie ich am besten beurteilen konnte, gab es keine Möglichkeit, nur das background-image(was ich brauchte) zu drehen , also musste ich einige zusätzliche divElemente hinzufügen , um das richtige zu erhalten / linke Seiten des Hex, so dass ich dann die Pseudoelemente als background-imageRotationsmittel verwenden konnte.

Ich habe in IE9, FF und Chrome getestet. Theoretisch sollte jeder Browser, der CSS3 unterstützt transform, funktionieren.

Erstes Hauptupdate (Erklärung hinzugefügt)

Ich habe jetzt etwas Zeit, um eine Code-Erklärung zu veröffentlichen.

Erstens werden Sechsecke durch 30/60-Grad-Beziehungen und Trigonometrie definiert, sodass dies die Schlüsselwinkel sind. Zweitens beginnen wir mit einer "Zeile", in der sich das Hex-Raster befinden soll. Der HTML-Code ist definiert als (die zusätzlichen divElemente helfen beim Erstellen des 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>

Wir werden inline-blockfür das Sechseck verwenden display, aber wir möchten nicht, dass sie versehentlich in die nächste Zeile umbrechen und das Gitter ruinieren, also white-space: nowraplösen Sie dieses Problem. Der marginWert in dieser Zeile hängt davon ab, wie viel Platz zwischen den Feldern benötigt wird. Möglicherweise sind einige Experimente erforderlich, um das zu erhalten, was Sie möchten.

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

Mit den unmittelbaren Kindern der Elemente, .hexrowdie nur divElemente sind, bilden wir die Grundlage für die Hex-Form. Das widthtreibt die Horizontale der Oberseite des Sechsecks an, das heightwird von dieser Zahl abgeleitet, da alle Seiten auf einem regulären Sechseck gleich lang sind. Auch hier wird der Rand vom Abstand abhängen, aber hier wird die "Überlappung" der einzelnen Sechsecke auftreten, damit das Gitter aussieht. Das background-imagewird hier einmal definiert. Die Verschiebung nach links dient dazu, mindestens die hinzugefügte Breite für die linke Seite des Sechsecks aufzunehmen. Angenommen, Sie möchten zentrierten Text, text-alignbehandelt der (natürlich) den horizontalen, aber der line-height, der mit dem übereinstimmt height, ermöglicht eine vertikale Zentrierung.

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

Jedes ungerade Hex-Feld wird in Bezug auf die "Reihe" nach unten und jedes gerade nach oben verschoben. Die Verschiebungsberechnung (Breite x cos (30) / 2) ist ebenfalls dieselbe wie (Höhe / 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)) */
}

Wir verwenden 2 untergeordnete divElemente, um die "Flügel" des Hex zu erstellen. Sie haben die gleiche Größe wie das Haupthex-Rechteck, werden dann gedreht und "unter" das Haupthex geschoben. Background-imagewird vererbt, so dass das Bild (natürlich) das gleiche ist, da das Bild in den "Flügeln" mit dem im Hauptrechteck "ausgerichtet" wird. Die Pseudoelemente werden verwendet, um die Bilder zu erzeugen, da sie wieder in die Horizontale "umgedreht" werden müssen (da wir die übergeordneten Elemente gedreht divhaben, um die "Flügel" zu erstellen).

Der :beforeerste übersetzt seinen Hintergrund um die Breite des negativen Betrags, der dem Hauptteil des Hexfelds plus der ursprünglichen Hintergrundverschiebung des Haupthexfelds entspricht. Der :beforezweite ändert den Ursprungspunkt der Translation und verschiebt die Hauptbreite auf der x-Achse und die halbe Höhe auf der y-Achse.

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

Hier befindet spansich Ihr Text. Das line-heightwird zurückgesetzt, um die Textzeilen normal zu machen, aber das vertical-align: middlefunktioniert, da das line-heightauf dem übergeordneten Text größer war. Das white-spacewird zurückgesetzt, damit es wieder umbrochen werden kann. Der linke / rechte Rand kann auf negativ gesetzt werden, damit der Text in die "Flügel" des Hexfelds gelangen kann.

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

Sie können einzelne Zielzeilen und -zellen in diesen Zeilen einzeln ändern, um Bilder, spanTexteinstellungen oder Deckkraft zu ändern oder ein größeres Bild aufzunehmen (um es an die gewünschte Stelle zu verschieben) usw. Dies geschieht im Folgenden für die zweite Zeile.

.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;
}
ScottS
quelle
1
Vielen Dank, dass Sie eine so gut erklärte, gründliche und geniale Antwort gegeben haben. Das ist großartig!
Element119
@ScottS Ich hatte das seltsamste Problem bei der Implementierung. Ich verwende das Bootstrap-Toolkit von Twitter und irgendwie sieht es immer so aus . Ich habe das Problem auf Folgendes reduziert div.container: Das Layout wird durcheinander gebracht, wenn sich das Sechseck in diesem Container-Div befindet. Das Seltsame ist jedoch, den Vergleich zwischen den einzelnen Szenarien zu betrachten: Link und Link . Ich habe einige Tests durchgeführt, aber ich kann nicht herausfinden, was die Sechsecke durcheinander bringt!
Element119
@ Archio - Zuerst zeigen Sie den Code für das Kind der ersten Ebene der Hex-Zeile an, aber das Problem ist wahrscheinlich bei den Kindern der zweiten Ebene, die die "Flügel" des Hex erzeugen, da dies der Teil des Bildes ist, der fehlt ( ich kann also nicht debuggen). Das Problem könnte dort gewesen sein (und overflow: hiddenwürde tun, was Sie zeigen), aber das scheint nicht so zu sein. Schauen Sie sich die Verschachtelung der zweiten Ebene divund ihren :beforeCode an, da sich wahrscheinlich entweder das divin der Transformation nicht dreht oder background-imagedas sowohl das divals auch das :beforePseudoelement nicht erbt .
ScottS
Ich habe es gerade überprüft - beide scheinen die Hintergrundfarbe ( Link ) zu erben . Sie drehen sich auch. Ich kann sehen, dass sie im Chrome Web Inspector gedreht werden. Das Problem ist, dass sie einfach nicht angezeigt werden, obwohl sie es haben display:block.
Element119
Ah, ich glaube ich habe es gefunden! Sieht aus wie das Problem war z-index. Ich optimiere es jetzt, um sicherzustellen, dass alles richtig funktioniert.
Element119
53

Es kann tatsächlich mit nur einem Element pro Sechseck und Pseudoelementen für das Hintergrundbild und den Text durchgeführt werden.

Demo

Grundlegende HTML- Struktur:

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

Sie können möglicherweise mehr Zeilen haben, Sie müssen nur nSechsecke in ungeraden Reihen und n+/-1Sechsecke in geraden Reihen haben.

Relevantes 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); 
}
Ana
quelle
5
Das verdient wirklich mehr Upvotes! So knapp und einfach, und die Demo zeigt wirklich die Vielseitigkeit. Der einzige Nachteil kann sein, dass der Inhalt in einem Attribut und nicht im Element selbst gespeichert wird.
Thomas W
Sie können den Inhalt in ein untergeordnetes Element einfügen :) Ich wollte nur die Anzahl der hier benötigten HTML-Elemente minimieren. Ein untergeordnetes Element mit tatsächlichem Inhalt kann jedoch problemlos anstelle des Pseudos verwendet werden.
Ana
2
Sie haben Recht, im Grunde muss nur durch ersetzt .content:afterwerden .hexagon > *. Genial.
Thomas W
Irgendwelche Gedanken darüber, wie die Ränder zwischen den Sechsecken elegant verändert werden könnten?
Maxheld
Seltsamerweise
2

Ich werde eine einfache Demo zum Erstellen einer sechseckigen Form bereitstellen.

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

Starx
quelle
1

Hier ist ein weiterer Ansatz mit COMPASS / SCSS, mit dem die Größe und das Layout der Sechsecke einfach eingestellt werden können:

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

Interdruper
quelle
0

Wenn Sie in der Lage sind, den Div-Shap-Trick zu implementieren, geben position:relativeSie einfach jedem Div ein (Sie müssten sie zunächst alle einzeln positionieren, indem Sie auch topund setzen left).

RozzA
quelle
Können Sie ein Beispiel in einer JSFiddle geben? Der Div-Shap-Trick funktioniert nicht wirklich, wenn ich das Sechseck mit Bildern und Text füllen muss.
Element119
1
Ja, Sie können nur einfarbige Formen erstellen: jsfiddle.net/Exceeder/cVqtW Es ist nicht möglich, diese Divs als Beschneidungsbereiche für Hintergrundbilder oder zum Formen von Text zu verwenden.
Alex Pakka
0

Sie können ein vollständig ansprechendes hexagonales Raster nur mit CSS erstellen. Die Idee ist, mithilfe des CSS2.1-Überlaufs eine übergeordnete Form als Maske zu erstellen: versteckt, die mit fast allen Browsern kompatibel ist, sogar mit dem Internet Explorer 6.

Es ist eine überraschend einfache Technik, mit der ein ansprechendes Gitter mit allen Arten von Formen erstellt werden kann. Um das Problem zu lösen, muss nur über den Tellerrand hinaus gedacht werden.

Ich habe hier eine ausführliche Schritt-für-Schritt-Anleitung zur Durchführung dieser Technik: https://www.codesmite.com/article/how-to-create-pure-css-hexagonal-grids

Dies ist der beste Weg, den ich bisher gefunden habe, erfordert kein Javascript und ist sowohl flüssig als auch reaktionsschnell.

Ich habe die Technik auch in einer kostenlosen HTML-Vorlage verwendet, die Bilder in den Sechsecken enthält, die Sie hier testen und herunterladen können: https://www.codesmite.com/freebie/hexa-free-responsive-portfolio-template

Asche
quelle
-2

AFAIK, in reinem CSS gibt es keine Möglichkeit. Am besten verwenden Sie Maskenausschnitte für Hintergründe, wie hier erläutert: http://www.cssbakery.com/2009/06/background-image.html (dies funktioniert nur, wenn Ihr Seitenhintergrund einfarbig ist oder Sie passen können und positionieren Sie Ihre Maske so, dass sie mit dem Seitenhintergrund übereinstimmt.

Dann könnten Sie csstextwrap verwenden, um in den Text zu passen: http://www.csstextwrap.com/examples.php

Es gab eine Reihe ähnlicher Fragen zu SO. ZB Gibt es eine Möglichkeit, Text in div eine Dreiecksform ausfüllen zu lassen?

Alex Pakka
quelle
Alex, wollte nur, dass du weißt, dass es in reinem CSS3 eine Möglichkeit gibt (siehe meine Antwort).
ScottS