5202

ein Blog über technische Fragen zu Blogger

Sidebar Tabber ohne Javascript

von
Tabber (oder Wechselseiten) sind eine zweischneidige Sache ... einerseits sind sie Platzsparrend ... andererseits wirken sie in vielen Layouts auf mich wie Fremdkörper.

Tabber kommen ursprünglich aus der Desktop-Windows-Welt und sind für das Web adaptiert worden - vielleicht ist dass das Problem :).

Ich habe mich auf Bitten eines Lesers auf jeden Fall mal an so ein Tabber gewagt und eine Wechselseite ganz ohne Javascript gebaut - die Skizze funktioniert auch in mobilen Browsern!

Vorbemerkung

Ich verwende in der Skizze verschiedene Hacks und Tricks - ich gebe eine etwas ausführlichere Erklärung dafür, damit das 'Warum' besser verständlich wird. Ich versuche außerdem was neues und erkläre CSS/HTML im Zusammenhang und nicht hintereinander ... mal sehen, ob's damit besser verständlich wird.

Wrapper

Roll on - das ganze Gadget kommt in ein Wrapper. Weil wir in der Skizze floaten, legen wir unten einen Div-Container mit clear: both rein - sicher ist sicher :):
<div id="tabber">

  <div style="clear: both"></div>
</div>
Weil wir mit position: absolute Eigenschaften arbeiten, müssen wir zwingend dem Element eine Mindesthöhe geben - sonst kollabiert die Sidebar:
#tabber {
    display: block;
    position: relative;
    min-height: 260px;
}
Wir verwenden in dieser Skizze außerdem für alle HTML Elemente die border-sizing Eigenschaft border-box.
#tabber,
.tab,
.content_inner,
label {
    -webkit-box-sizing: border-box;
       -moz-box-sizing: border-box;
            box-sizing: border-box;
}
Dadurch ersparen wir uns später das nervige Umrechnen mit Padding, Margin und Border ...

Die Input-Elemente

In den Wrapper kommen nun drei input Elemente mit dem dazugehörigen Label:
<div id="tabber">
    <div class="tab">
           <input type="radio" id="tab-1" name="tab-group-1" checked="checked" >
           <label for="tab-1">About</label>
    </div>
    <div class="tab">
           <input type="radio" id="tab-2" name="tab-group-1" >
           <label for="tab-2">Where?</label>
    </div>
    <div class="tab">
           <input type="radio" id="tab-3" name="tab-group-1">
           <label for="tab-3">What?</label>
    </div>
  <div style="clear: both"></div>
</div>
Die dazugehörigen Div-Container bekommen nun eine _feste_ Weite und Höhe - außerdem werden sie nach Rechts gefloatet:
.tab {
    float: left;
    position: relative;
    width: 160px;
    height: 40px;
    margin-left: -1px;
    left: 1px;
    text-align: center;
    margin: 0;
    padding: 0;
}
margin-left: -1px ist ein Hack, um in älteren Browser das Kollabieren der Tabs nach Rechts zu verhindern. Außerdem normalisieren wir die inneren und äußeren Abstände noch mal (ist wegen der Blogger-CSS notwendig).
Der Input-Hack
Jetzt kommt etwas sehr cleveres, wir nehmen nämlich zum 'klicken' nicht die Labels, sondern das input Element - Grund ist, das input Element lässt sich auch in mobilen Browsern klicken, Labels dagegen nicht.

  .tab input {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 100;
        opacity: 0;
        cursor: pointer;
    }

Das input Element nimmt damit die volle Fläche des Tabs ein, liegt wegen des Z-Index ganz oben und wird dann mit opacity 'Durchsichtig' gemacht, d.h. ihr seht es nicht mehr, könnt es aber nach voll benützen.

Jetzt noch a bisserl Style:
 .tab  label {
        display: block;
        width: 100%;
        height: 100%;
        background: #eee;
        border: 1px solid #ccc;
        border-radius: 10px  10px 0 0;
        line-height: 40px;
    }

Der Innencontainer

Zuletzt legen wir unter jedem Label noch einen Div-Container, der den Inhalt des Tabbers trägt:
<div id="tabber">
<div class="tab">
           <input type="radio" id="tab-1" name="tab-group-1" checked="checked" >
           
<label for="tab-1">About</label>
<div class="content_inner"><span>All about Me!</span></div>
</div>
<div class="tab">
           <input type="radio" id="tab-2" name="tab-group-1" >
           <label for="tab-2">Where?</label>
<div class="content_inner"><span>Where do i come frome?</span></div>

</div>
<div class="tab">
           <input type="radio" id="tab-3" name="tab-group-1">
           <label for="tab-3">What?</label>
<div class="content_inner"><span>Should i cry like a baby or die like a man?</span></div>

</div>
<div style="clear: both"></div>
</div>
Die Breite des Innencontainers ist 3x Breite/Tabs (3x160px = 480px)
.content_inner {
    width: 480px;
    height: 200px;
    position: absolute;
    left: 0;
    border: 1px solid #ccc;
    overflow: hidden;
    z-index: -1;
}
Die Elemente _innerhalb_ des Innencontainers werden ausgeblendet:
.content_inner > * {
        position: relative;
        opacity: 0;
        z-index: -1;
    }
Der Universalselektor * ist ein Trick und erlaubt uns, jede Art von Inhalt in den Container zu legen ... Bilder, Links, Text whatever - alles wird ausgeblendet.

Zuletzt brauchen wir noch einen Korrekturwert, um die einzelnen Container exakt übereinander zu bekommen:
#tab-1 ~ .content_inner { left: 0 }
#tab-2 ~ .content_inner { left: -160px }
#tab-3 ~ .content_inner { left: -320px }
Jeder Container wird dabei um eine Tab'breite' nach links verschoben - verständlich, oder?

Checkbox ist :checked

Kommen wir zum spannenden Teil - was passiert, wenn ein input Element gedrückt wird, d.h. die Eigenschaft :checked bekommt?
#tab-1:checked ~ .content_inner,
#tab-2:checked ~ .content_inner,
#tab-3:checked ~ .content_inner {
    background: #fff;
    z-index: 10;
    border-top: #fff;
}
input:checked ~ .content_inner > * {
    position: relative;
    opacity: 1;
    z-index: 10;
}
input:checked ~ label {
    background: #fff;
    border-bottom: #fff;
}
Wir verändern Hintergrund und Linien so, dass der Eindruck einer 'gemeinsamen' Fläche zwischen Tab und Innencontainer entsteht. Außerdem wird der Innenbereich sichtbar ...
Smooth
... aber auf ein ganz langweilige Art, der Innenbereich wird halt sichtbar. So what? Nicht besonders spannend, oder? Deswegen legen wir jetzt noch eine smoothe Bewegung drauf:
 #tab-1 ~ .content_inner > *,
    #tab-3 ~ .content_inner > * {
        position: relative;
        margin-left: -400px;
        text-align: center;
        line-height: 200px;
        -webkit-transition: margin-left 1.6s ease;
           -moz-transition: margin-left 0.6s ease;
            -ms-transition: margin-left 0.6s ease;
             -o-transition: margin-left 0.6s ease;
    }
#tab-2 ~ .content_inner > * {
    position: relative;
    margin-left: 400px;
    text-align: center;
    line-height: 200px;
    -webkit-transition: margin-left 0.6s ease;
       -moz-transition: margin-left 0.6s ease;
        -ms-transition: margin-left 0.6s ease;
         -o-transition: margin-left 0.6s ease;
}
   #tab-1:checked ~ .content_inner > *,
    #tab-2:checked ~ .content_inner > *,
    #tab-3:checked ~ .content_inner > * {
        margin-left: 0;
        -webkit-transition: margin-left 0.6s ease;
           -moz-transition: margin-left 0.6s ease;
            -ms-transition: margin-left 0.6s ease;
             -o-transition: margin-left 0.6s ease;
    }   
Im Grundzustand verschieben wir den Inhalt um 400px nach Rechts beziehungsweise Links ... wenn der Innenteil angezeigt wird, machen wir mit einer Transition die Verschiebung wieder rückgängig. Ziemlich simpel ... ursprünglich wollte ich den Tab mit einer Drehbewegung einblenden, aber das sparre ich mir für den nächsten Post auf ....

Ansonsten wär's das - mission accomplished!

Vom Code Erschlagen?

Ihr fragt euch gerade, ob's wirklich so ein gute Idee ist, ein Tabber mit CSS zu bauen ... yeah, lustigerweise hat heute ein Banknachbar über einen Tabber mit Javascript geschrieben ... vielleicht ist das ja was für euch?

Der unbestritten-beste-jemals-mit-Javascript-gebauter-Tabber-für-Blogger ist übrigens der von Greenlava.
Trotzdem CSS?
Obwohl es diese tollen Scripts gibt, würde ich es an eurer Stelle trotzdem mit einer reinen CSS Lösung versuchen, weil Javascript ein paar fiese Nebeneffekte hat, etwa bei iPad & Co. ziemliche Sprünge zu verursachen.

Javascript sollte immer nur dann verwendet werden, wenn es keine CSS Alternative gibt ... und inzwischen sind die Browser so weit, dass ihr das relativ unbefangen einsetzen könnt - die Skizze funktioniert in allen richtigen Browsern, auf allen mobilen Browsern und im IE ab 8+.

Fragen, Anmerkungen