Ein einfaches 12-Column-Layout mit Javascript

benjamin.fillei
19.07.18 | Benjamin Fillei

Bis dato war es „common practice“ Spalten- und Zeilenlayouts mittels Code-Bibliotheken wie zum Beispiel Bootstrap zu realisieren. Seit ungefähr einem Jahr gibt es nun auch die Möglichkeit das Gleiche nur mit css zu erreichen. Leider ist der Browsersupport für dieses Feature laut caniuse.com in Österreich noch immer nur bei knapp über 80%.

Für eine bessere Browser-Kompatibilität und weil ich Bootstrap wegen der vielen HTML-Klassen und den zahlreichen jQuery-Plugins etwas unhandlich finde, möchte ich euch Leserinnen und Lesern heute eine andere Methode vorstellen um ansprechende Layouts im Web zu gestalten.

Grundlage für das ganze ist das mächtige HTML Attribut „data“. Es gibt uns die Möglichkeit seinen Wert an eine Javascript-Variable zu übergeben. Damit kann man dann allerhand cooles zaubern.

<div data-dasisteindatenattribut="hallo"></div>

Den Wert „hallo“ kann man dann mittels Javascript beliebig verwenden. In diesem Fall geben wir ihn einfach als Text im Container wieder aus.

<script type="text/javascript">
    var divs = document.querySelectorAll("[data-dasisteindatenattribut]");
    var wert = divs[0].dataset.dasisteindatenattribut;
    divs[0].innerHTML = wert;
</script>

Ausgabe:

Als nächstes wenden wir dieses Konzept an um eine Layoutelement und drei Spaltenelemente zu definieren. Das Layout (data-layout) bekommt als Wert eine maximale Anzahl an Spalten und einen Spaltenabstand (auch „gutter“ genannt). Mit dem Wert der Spaltenelemente (data-wrap) legen wir fest, welche Spalten sie umfließen sollen. Wir beginnen damit alle Layouts in einer Variable zu speichern. Die „clearfix“ Klasse ist notwendig um die „floats“ der „Child-Elemente“ aufzulösen.

<style type="text/css">
    .clearfix::after {
        content: " "; 
        display: block; 
        height: 0; 
        clear: both;
    }
</style>

<div class="clearfix" data-layout="12,1" style="width: 100%; margin-top: 10px; margin-bottom: 10px; z-index: 1;">
    <div data-wrap="0-2" style="background-color: orange; height: 100px;"></div>
    <div data-wrap="2-8" style="background-color: lime; height: 100px;"></div>
    <div data-wrap="8-12" style="background-color: lightBlue; height: 100px;"></div>
</div>

<script type="text/javascript">
    var layouts;
    layouts = document.querySelectorAll("[data-layout]");
</script>

Nun durchkämmen wir mit einer verschachtelten for-Schleife alle in dieser Variable gespeicherten Layouts und alle in ihnen enthaltenen Elemente, welche Spalten umfließen und speichern den Wert ihrer data-Attribute in die Variablen „maxColumns“, „gutter“, „columnStart“ und „columnEnd.

<script type="text/javascript">
    var layouts, 
        currentLayout, 
        maxColumns, 
        gutter, 
        elements, 
        currentElement, 
        columnStart, 
        columnEnd,
        columns;

    //layouts durchkämmen
    layouts = document.querySelectorAll("[data-layout]");
    for (var i = 0; i <= layouts.length - 1; i++) {
        currentLayout = layouts[i];
        
        maxColumns = parseInt(currentLayout.dataset.layout.split(',')[0]);
        gutter = currentLayout.dataset.layout.split(',')[1];
        
        //Elemente im momentanen Layout durchkämmen
        elements = currentLayout.children;
        for (var j = 0; j <= elements.length - 1; j++) {
            currentElement = elements[j];
            
            //wenn es sich um ein Element mit data-wrap handelt, dann...
            if(currentElement.dataset.wrap){
                columnStart = parseInt(currentElement.dataset.wrap.split('-')[0]);
                columnEnd = parseInt(currentElement.dataset.wrap.split('-')[1]);
                columns = columnEnd - columnStart;
            }
        }
    }
</script>

Zum Schluss geben wir den Elementen basierend auf den vorhin erstellten Variablen die nötigen Styles und Ausnahmen. Das if-else-Statement überprüft, ob das momentane Element hinter dem vorherigen noch Platz hat, oder bereits in die nächste Zeile gehört.

<script type="text/javascript">
    var layouts, 
        currentLayout, 
        maxColumns, 
        gutter, 
        elements, 
        currentElement, 
        columnStart, 
        columnEnd,
        columns,
        lastElementColumnEnd = 0;
    
    //layouts durchkämmen
    layouts = document.querySelectorAll("[data-layout]");
    for (var i = 0; i <= layouts.length - 1; i++) {
        currentLayout = layouts[i];
        
        maxColumns = parseInt(currentLayout.dataset.layout.split(',')[0]);
        gutter = parseInt(currentLayout.dataset.layout.split(',')[1]);
        
        //Elemente im momentanen Layout durchkämmen
        elements = currentLayout.children;
        for (var j = 0; j <= elements.length - 1; j++) {
            currentElement = elements[j];
            
            //wenn es sich um ein Element mit data-wrap handelt, dann...
            if(currentElement.dataset.wrap){
                columnStart = parseInt(currentElement.dataset.wrap.split('-')[0]);
                columnEnd = parseInt(currentElement.dataset.wrap.split('-')[1]);
                columns = columnEnd - columnStart;
                
                //Hier wird das Element Positioniert
                currentElement.style.position = "relative";
                currentElement.style.float = "left";
                currentElement.style.width = (100/maxColumns)*columns-gutter+"%";
                
                //Hier wird überprüft, ob das nächste Element neben dem Vorherigen noch Platz hat oder nicht
                if(100/maxColumns*columnStart-lastElementColumnEnd >= 0){
                    currentElement.style.marginLeft = 100/maxColumns*columnStart-lastElementColumnEnd+gutter/2+'%';
                    currentElement.style.clear = 'none';
                } else { 
                    currentElement.style.marginLeft = 100/maxColumns*columnStart+gutter/2+'%'; 
                    currentElement.style.clear = 'both';
                }
                currentElement.style.marginRight = gutter/2+'%';
                lastElementColumnEnd = 100/maxColumns*columnEnd;
            }
        }
    }
</script>

... und voilà!

Zur besseren Visualisierung habe ich die drei Elemente noch mit zwölf weiteren überlagert, die jeweils eine Spalte umfließen.


Ausgabe:

Mit diesem Code lassen sich allerhand coole Layouts realisieren. Der Einfachheit halber habe ich hier auf Eingabeverifizierung und Error-Benachrichtigungen verzichtet – damit könnt ihr gerne selbst experimentieren.

Viel Spaß!

Voriger Blogeintrag
Nächster Blogeintrag