Pure CSS Pentagon

Wie baut man mit CSS ein Fünfeck?

Per “background-image”, werden bestimmt einige denken, aber nein, ich möchte ein richtiges CSS-Fünfeck. Und einen Schatten soll es werfen, was die Sache natürlich zusätzlich verkompliziert.

Wir fangen an mit dem html-Kram:

<!DOCTYPE html>
<html>
<head>
  <style type="text/css">
    <!... Hier kommen die CSS-Styles hin ...>
  </style>
  <title>Pentagon</title>
</head>
<body>
    <!... und hier die HTML-Tags, die noch gebraucht werden ...> 
</body>

Zuerst brauchen wir einen Container…

<div class="pentagon-container">
  ...
</div>

…zum in die Mitte schieben mit “margin: auto;”. Also fügen wir in das Style-Tag diese CSS-Regel ein:

.pentagon-container {
  width: 200px;
  height: 190px;
  margin:  auto;
  background: #222222;
  position:  relative;
}

Die Eigenschaft “position: relative;” setzten wir, damit wir später mit “position: absolute;” Child-Elemente in Relation zu diesem Container ausrichten können.

Nun kommt in den Container das eigentliche Fünfeck hinein…

<div class="pentagon-container">
  <div class="pentagon pentagon1"></div>
  <div class="pentagon pentagon2"></div>
</div>

…und wird im Folgenden mit CSS in Form gebracht.

Leider ist es meines Wissens nicht möglich, ein Fünfeck aus einem einzelnen HTML-Element zu gestalten – abgesehen von einer Variante mit Pseudoelement, die aber, soweit ich das sehe, keinen wesentlichen Vorteil bringt. Deshalb verwenden wir zwei HTML-Elemente, die wir direkt untereinander positionieren.

Wir werden zuerst aus “<div class=”pentagon1″>” ein sehr flaches Dreieck und dann aus “<div class=”pentagon2″>” ein sich nach unten verjüngendes Trapez bilden, das die Dreiecksform zu einem Fünfeck ergänzt.

Ein Dreieck lässt sich mit CSS mithilfe der border-Eigenschaft bilden. Dazu bekommt das Element eine Höhe und eine Breite von 0px, dafür aber Ränder, etwa so..

.pentagon {
  position: absolute;
  width:  0;
  height:  0;
}
.pentagon1 {  
  border-left: solid 100px #2F4F4F;
  border-right: solid 100px #2F4F4F;
  border-bottom: solid 70px #8A795D;
}

Es empfiehlt sich im übrigen fast immer, Eigenschaften, die auf mehrere Elemente angewandt werden sollen, in eine eigene Style-Klasse auszulagern. Das ist hier auch geschehen.

Mit “position: absolute;” wird das Element an dem nächsthöheren Parent-Element ausgerichtet, das eine Positionierung mit “position: …;” aufweist. Das ist in unserem Fall der Container, wofür wir ja gesorgt haben.

Breite und Höhe sind auf 0 gesetzt, Dafür haben wir links, rechts und unten Ränder definiert. Die Ränder links und rechts sind nur zur Veranschaulichung eingefärbt, später werden sie transparent.

Das Ganze sieht nun so aus:

Wie man sieht ist der Container schwarz eingefärbt, auf der gleichen Position – per default ausgerichtet an der linken, oberen Ecke – befindet sich auch das Dreieck, dessen Ränder noch transparent werden müssen.

Erstmal ergänzen wir aber noch das Trapez, das ja aus dem zweiten HTML-Element entstehen soll.

.pentagon2 {
  top: 70px;
  width: 130px;
  border-left: solid 35px #2F4F4F;
  border-right: solid 35px #2F4F4F;
  border-top: solid 120px #8A795D;
}

Die Eigenschaften “position” und “height” borgen wir uns von der Klasse “pentagon”.

Diesmal brauchen wir allerdings eine Breite von 130px, damit das Fünfeck so halbwegs regelmässig wird. Hier hab ich das per Augenmaß entschieden, natürlich lässt es sich auch nachrechnen, was aber wieder eine andere Geschichte wäre.

Mithilfe der border-Eigenschaften haben wir das Trapez geformt und mithilfe von “top: 70px;” so positioniert, dass es direkt unterhalb unseres Dreiecks angezeigt wird.

Nun entfernen wir den Container-Hintergrund und setzen diejenigen Elemente, die wir nicht brauchen, auf transparent…

<!DOCTYPE html>
<html>
<head>
  <style type="text/css">
    <!... Hier kommen die CSS-Styles hin ...>
    .pentagon-container {
      width: 200px;
      height: 190px;
      margin:  auto;
      position:  relative;
    }
    .pentagon {
      position: absolute;
      width: 0;
      height: 0;
    }
    .pentagon1 {  
      border-left: solid 100px transparent;
      border-right: solid 100px transparent;
      border-bottom: solid 70px #8A795D;
    }
    .pentagon2 {
      top: 70px;
      width: 130px;
      border-left: solid 35px transparent;
      border-right: solid 35px transparent;
      border-top: solid 120px #8A795D;
  }
  </style>
  <title>Pentagon</title>
</head>
<body>
  <!... und hier die HTML-Tags, die noch gebraucht werden ...>
  <div class="pentagon-container">
    <div class="pentagon pentagon1"></div>
    <div class="pentagon pentagon2"></div>
  </div> 
</body>

und erhalten…

Jetzt fehlt noch der Schatten. Blöderweise können wir nicht die gängige Eigenschaft “box-shadow” verwenden, da diese den von uns generierten Formen nicht folgt.

Wir müssen uns deshalb anderweitig behelfen. Eine einfache Möglichkeit besteht darin, schlicht ein weiteres Fünfeck hinter dem schon implementierten zu setzen, dieses mithilfe eines blur-Effekts und einer grauen Hintergrundfarbe schattenartig zu gestalten und ein wenig nach rechts unten zu verschieben.

Der HTML-Code wird ergänzt um…

  <div class="pentagon pentagon-shadow pentagon1 pentagon-shadow1"></div>
  <div class="pentagon pentagon-shadow pentagon2 pentagon-shadow2"></div>

Da wir faul sind, verwenden wir die CSS-Eigenschaften für die HTML-Elemente, die das Fünfeck bilden, nochmal und ergänzen lediglich diejenigen Eigenschaften, die daraus einen Schatten machen…

.pentagon-shadow {
  border-bottom-color: gray;
  left: 12px
  
  filter:blur(4px);
    -o-filter:blur(4px);
    -ms-filter:blur(4px);
    -moz-filter:blur(4px);
    -webkit-filter:blur(4px);
}

.pentagon-shadow1 {
  top: 12px;
  border-bottom-color: gray;
}

.pentagon-shadow2 {
  top: 82px;
  border-top-color: gray;
}

Das kennen wir im Grunde schon. Mit “top: …;” und “left: …;” wurden die beiden Schatten-Elemente um jeweils12px nach rechts unten verschoben, die Farbe wurde auf “gray” gesetzt und mithilfe eines Filters wurde ein blur-Effekt angewendet.

Der gesamte Code sieht nun so aus…

<!DOCTYPE html>
<html>
<head>
  <style type="text/css">
    <!... Hier kommen die CSS-Styles hin ...>
    .pentagon-container {
      width: 200px;
      height: 190px;
      margin:  auto;
      position:  relative;
    }
    .pentagon {
      position: absolute;
      width:  0;
      height:  0;
    }
    .pentagon1 {  
      border-left: solid 100px transparent;
      border-right: solid 100px transparent;
      border-bottom: solid 70px #8A795D;
    }
    .pentagon2 {
      top: 70px;
      width: 130px;
      border-left: solid 35px transparent;
      border-right: solid 35px transparent;
      border-top: solid 120px #8A795D;
    }
    .pentagon-shadow {
      left:  12px;
  
      filter:blur(4px);
      -o-filter:blur(4px);
      -ms-filter:blur(4px);
      -moz-filter:blur(4px);
      -webkit-filter:blur(4px);
    }
    .pentagon-shadow1 {
      border-bottom-color: gray;
      top:  12px;
    }
    .pentagon-shadow2 {
      top: 82px;
      border-top-color: gray;
    }
  </style>
  <title>Pentagon</title>
</head>
<body>
  <!... und hier die HTML-Tags, die noch gebraucht werden ...>
  <div class="pentagon-container">
    <div class="pentagon pentagon1 pentagon-shadow pentagon-shadow1"></div>
    <div class="pentagon pentagon2 pentagon-shadow pentagon-shadow2"></div>
    <div class="pentagon pentagon1"></div>
    <div class="pentagon pentagon2"></div>
  </div> 
</body>

Jetzt fehlt nur noch das Resultat. Voilà…

Kleine Anmerkung zum Schluß:

Hrm, okay, zugegebenermassen hätte die Variante mit einem CSS-Pseudoelement anstatt des zweiten DIV doch einen Vorteil gehabt. Dort würde der Schatten nämlich tatsächlich als Einheit gezeigt.

Da CSS-Pseudoelemente aber die ein oder andere Erklärung verlangen, würde das den Rahmen dieser Geschichte sprengen, deshalb ein andermal…

Hier ein Link zum Projekt mit Pseudoklasse auf www.liveweave.com