CSS-Fortschrittsbalken

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Ich habe einige Fortschrittsbalken erstellt. Sie sehen so aus

Sie verwenden keine Bilder, nur CSS3-Spielereien. Wie ein guter kleiner Designer es immer tut, fallen sie auf ein absolut akzeptables Erlebnis zurück. Hier sehen sie in Opera 11 aus, der einige der hier verwendeten CSS3-Funktionen unterstützt, aber nicht alle.

Wie Sie sich vorstellen können, sehen sie in Browsern, die überhaupt keine CSS3 unterstützen, ähnlich wie oben aus, nur noch weiter vereinfacht.

UPDATE: Es ist eine Weile her. Dieser Artikel wurde ursprünglich 2011 verfasst und 2015, und jetzt wieder 2021 aktualisiert. Diesmal erstelle ich nur das Demo und den Pen und entferne viel von dem Vendor-Prefix-Kram, der nicht mehr benötigt wird. Semantisch gesehen sind Sie wahrscheinlich besser dran, sich die Elemente <progress> und <meter> anzusehen.

HTML-Basis

Der Balken selbst wird ein <div> mit der Klasse meter sein. Darin befindet sich ein <span>, der als „gefüllter“ Bereich des Fortschrittsbalkens fungiert. Dies wird mit einem Inline-Stil gesetzt. Es ist das Markup, das weiß, wie weit ein Fortschrittsbalken gefüllt werden soll, daher ist dies ein Fall, in dem Inline-Stile perfekt Sinn ergeben. Die CSS-Alternative wäre, Klassen wie „fill-10-percent“, „fill-one-third“ oder ähnliches zu erstellen, was aufwendiger und weniger flexibel ist.

Das Grundlegende

<div class="meter">
  <span style="width: 25%"></span>
</div>

Beginn von CSS

Der Div-Wrapper ist die Spur des Fortschrittsbalkens. Wir setzen keine Breite, sodass er sich als Blockelement so breit wie sein Elternteil dehnt. Das könnten Sie aber tun. Die Höhe ist ebenfalls beliebig. Sie ist hier auf 20px eingestellt, könnte aber auch alles andere sein. Wir runden die Ecken in so vielen Browsern wie möglich ab und setzen einen Innenabstandsschattierung, um ihm einen Hauch von Tiefe zu verleihen.

.meter { 
  height: 20px;  <em>/* Can be anything */</em>
  position: relative;
  background: #555;
  border-radius: 25px;
  padding: 10px;
  box-shadow: inset 0 -1px 1px rgba(255, 255, 255, 0.3);
}

Der Span darin wird der Füllteil des Fortschrittsbalkens sein. Wir lassen ihn als Block mit 100% Höhe anzeigen, sodass er sich anpasst, egal wie viel Platz er hat. Wir verwenden dann eine Menge CSS3, um ihm einen Gradienten-Look zu verleihen und seine Ecken abzurunden.

.meter > span {
  display: block;
  height: 100%;
  border-top-right-radius: 8px;
  border-bottom-right-radius: 8px;
  border-top-left-radius: 20px;
  border-bottom-left-radius: 20px;
  background-color: rgb(43,194,83);
  background-image: linear-gradient(
    center bottom,
    rgb(43,194,83) 37%,
    rgb(84,240,84) 69%
  );
  box-shadow: 
    inset 0 2px 9px  rgba(255,255,255,0.3),
    inset 0 -2px 6px rgba(0,0,0,0.4);
  position: relative;
  overflow: hidden;
}

Das ist das Grundlegende.

Andere Farben

Wir machen es so einfach wie möglich, die Farbe zu ändern. Fügen Sie einfach einen Klassennamen wie „orange“ oder „red“ zum Div-Wrapper hinzu und die Farbe wird überschrieben.

.orange > span {
  background-color: #f1a165;
  background-image: linear-gradient(to bottom, #f1a165, #f36d0a);
}

.red > span {
  background-color: #f0a3a3;
  background-image: linear-gradient(to bottom, #f0a3a3, #f42323);
}

Kandystriping

Wir können einen coolen gestreiften Effekt erzielen, indem wir ein weiteres Element über diesen Span legen und einen wiederholten CSS3-Gradienten darüber legen. Semantisch lässt sich dies am besten mit einem Pseudoelement erreichen, also machen wir es auf diese Weise. Wir positionieren es absolut über den exakten Bereich des Spans (der bereits relativ positioniert ist) und runden die Ecken gleichmäßig, damit die Streifen nicht seltsam hervorstehen.

.meter > span:after {
  content: "";
  position: absolute;
  top: 0; left: 0; bottom: 0; right: 0;
  background-image: linear-gradient(
    -45deg, 
    rgba(255, 255, 255, .2) 25%, 
    transparent 25%, 
    transparent 50%, 
    rgba(255, 255, 255, .2) 50%, 
    rgba(255, 255, 255, .2) 75%, 
    transparent 75%, 
    transparent
  );
  z-index: 1;
  background-size: 50px 50px;
  animation: move 2s linear infinite;
  border-top-right-radius: 8px;
  border-bottom-right-radius: 8px;
  border-top-left-radius: 20px;
  border-bottom-left-radius: 20px;
  overflow: hidden;
}

Diese Idee habe ich zuerst bei Lea Verou gesehen und übernommen.

Animierte Kandystripes

Nur Firefox 4 kann Pseudoelemente animieren, und nur WebKit kann Keyframe-Animationen durchführen. Wir stecken also leider in der Klemme, was die Animation dieser Streifen angeht. Wenn wir uns dafür entscheiden, fügen wir einen zusätzlichen Span hinzu und animieren dann diesen mit WebKit.

<div class="meter animate">
  <span style="width: 50%"><span></span></span>
</div>

Der Span wird exakt derselbe sein wie das Pseudoelement, also verwenden wir einfach die gleichen Werte…

.meter > span:after, .animate > span > span {

… und vermeiden doppelte Angaben

.animate > span::after {
  display: none;
}

Wir bewegen die Hintergrundposition um die Größe davon

@keyframes move {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: 50px 50px;
  }
}

Und das nennen wir Animation

.meter > span::after, .animate > span > span {
  animation: move 2s linear infinite;
}

Wir können die Animation auch an das Pseudoelement binden, sodass sie funktioniert, sobald WebKit dies unterstützt.

Animation der gefüllten Breite

Leider kann man nicht auf eine automatische oder natürliche Breite animieren, was uns vielleicht erlauben würde, von einem erzwungenen Nullpunkt zum Inline-Stil zu animieren.

@keyframes expandWidth {
   0% { width: 0; }
   100% { width: auto; }
}

Update 25.01.2012: Es stellt sich heraus, dass man kann zu einem Inline-Stil animieren. Lassen Sie einfach den „to“- oder „100%“-Endwert in den @keyframes weg.

Ich habe es an die Bug-Tracker der großen Browser gesendet, um es ein wenig voranzutreiben, aber vorerst ist es nicht unterstützt. Stattdessen machen wir es mit jQuery. Messen Sie die ursprüngliche Breite, zwingen Sie sie auf Null und animieren Sie dann wieder nach oben.

$(".meter > span").each(function() {
  $(this)
    .data("origWidth", $(this).width())
    .width(0)
    .animate({
      width: $(this).data("origWidth") // or + "%" if fluid
    }, 1200);
});

Und fertig.

Andere Ansätze

HEY?! Was ist mit HTML5?

Alter Kumpel. HTML5 hat spezielle Funktionen dafür. <progress> und <meter>! Ja, das stimmt, aber hier ist der Haken. Diese Elemente haben bereits ein sehr spezifisches Aussehen. Standardmäßig sehen sie wie Fortschrittsbalken aus, die anderswo auf der Plattform, auf der Sie sich befinden, verwendet werden. Zum Beispiel hier auf Mac

Sie können diese Standardformatierung so deaktivieren

progress {
  -webkit-appearance: none;
}

Damit können Sie das glänzende Aussehen der Standardformatierung entfernen, aber Sie können immer noch nur begrenzt viel tun. Sie können den Fortschrittsbalken im Inneren so ändern

progress::-webkit-progress-bar-value {
  -webkit-appearance: none;
  background: orangered;
}

... und auch damit sind die Möglichkeiten danach recht begrenzt. Um es noch schlimmer zu machen, sind die Dinge in den verschiedenen Browsern sehr unterschiedlich, sogar zwischen verschiedenen WebKit-Browsern. Pseudoelemente funktionieren ebenfalls inkonsistent. Ich hasse es, die Dinge so hängen zu lassen, aber das ist wirklich ein Thema für eine andere Zeit. Sagen wir einfach, für diese speziellen Fortschrittsbalken ist die Div/Span-Lösung vorerst die beste.