Beispiel:Boxmodell.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

<!DOCTYPE html> <html lang="de"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Boxmodell</title> <script>

     "use strict"
     // Custom-Element self-slider anlegen
     customElements.define('self-slider', class extends HTMLElement {
       // self-slider soll Formularelement sein
       static formAssociated = true;
       // Festlegen, welche Attribute überwacht werden sollen
       static get observedAttributes() {
         return ['legend', 'label', 'min', 'max', 'step', 'value'];
       }
       constructor() {
         // Element wird anlgelegt
         // super muss als erstes im constructor aufgerufen werden, super ruft den construcor der Elternklasse auf
         super(); 
         // Zugriff auf die ElementInternals, wird benötigt, um auf die Werte zuzugreifen, die mit dem Formular versendet werden.
         this.internals = this.attachInternals();
         // Schatten-DOM anlegen
           // mode: 'open' : Vom Dokument aus ist der Zugriff auf das Schatten-Dom möglich.
           // mode: 'closed' : Der Zugriff auf das Schatten-Dom ist nicht möglich.
         const shadow = this.attachShadow({mode: 'closed'});
         // Element für Inhalt, hier ein fieldset, anlegen und ins Schatten-DOM einhängen
         this.slider = document.createElement('fieldset');
         this.slider.setAttribute('part', 'fieldset');
         shadow.appendChild(this.slider);
         // CSS anlegen und ins Schatten-Dom einhängen
         // :host selektiert das Custom Element
         const style = document.createElement('style');
         style.textContent = `
           :host fieldset { max-inline-size: fit-content; }
           :host fieldset * { display: inline-block; vertical-align: top; margin: 0; padding: .1em}
           :host input { font-size: .9em; }
         `;
         shadow.appendChild(style);
         // Defaultwerte der Attribute setzen
         this.legendAttribute = ;
         this.labelAttribute = ;
         this.minAttribute = 0;
         this.maxAttribute = 100;
         this.stepAttribute = 1;
         this.valueAttribute = 0;
       }
       connectedCallback() {
         // Element wurde ins DOM eingehängt
         // Schatten-DOM aufbauen
         // Zufällige ID für das Number-Input, wird fürs Label benötigt
         const numberID = Math.random().toString().replace('0.',);
         // Legende
         this.legend = document.createElement('legend');
         this.legend.setAttribute('part', 'legend');
         if(this.legendAttribute.length) {
           this.legend.innerHTML = this.legendAttribute;
         }
         else {
           this.legend.setAttribute('hidden', 'hidden');
         }
         this.slider.appendChild(this.legend);
         // Label
         this.label = document.createElement('label');
         this.label.setAttribute('for', numberID);
         this.label.setAttribute('part', 'label');
         if(this.labelAttribute.length) {
           this.label.innerHTML = this.labelAttribute;
         }
         else {
           this.label.setAttribute('hidden', 'hidden');            
         }
         this.slider.appendChild(this.label);
         // Range-Input
         this.range = document.createElement('input');
         this.range.setAttribute('type', 'range');
         this.range.setAttribute('min', this.minAttribute);
         this.range.setAttribute('max', this.maxAttribute);
         this.range.setAttribute('step', this.stepAttribute);
         this.range.setAttribute('value', this.valueAttribute);
         this.range.setAttribute('part', 'range');
         this.slider.appendChild(this.range);
         // Number-Input
         this.number = document.createElement('input');
         this.number.setAttribute('id', numberID);
         this.number.setAttribute('type', 'number');
         this.number.setAttribute('min', this.minAttribute);
         this.number.setAttribute('max', this.maxAttribute);
         this.number.setAttribute('step', this.stepAttribute);
         this.number.setAttribute('value', this.valueAttribute);
         this.number.setAttribute('part', 'number');
         this.slider.appendChild(this.number);
         // Start-Value speichern und ans Formular übergeben
         this.currentValue = this.valueAttribute;
         this.internals.setFormValue(this.currentValue);
         // Eventhandler, um die beiden Inputs zu synchronisieren und den Wert zu speichern und ans Formular zu übergeben
         this.slider.addEventListener('input', event => {
           if(event.target.type == 'range') {
             this.number.value = event.target.value;
           }
           else if(event.target.type == 'number') {
             this.range.value = event.target.value;
           }
           this.currentValue= event.target.value;
           this.internals.setFormValue(this.currentValue);
         });
       }
       attributeChangedCallback(name, oldValue, newValue) {
         // Elementparameter wurden geändert
         // Achtung attributeChangedCallback wird vor connectedCallback aufgerufen, daher prüfen, ob Elemente schon vorhanden sind
         switch(name) { 
           case 'legend':
             this.legendAttribute = newValue;
             if(this.legend) {
               if(this.legendAttribute && this.legendAttribute.length) {
                 this.legend.removeAttribute('hidden');
                 this.legend.innerHTML = this.legendAttribute;
               }
               else {
                 this.legend.setAttribute('hidden','hidden');
               }
             }
             break;
           case 'label':
             this.labelAttribute = newValue;
             if(this.label) {
               if(this.labelAttribute && this.labelAttribute.length) {
                 this.label.removeAttribute('hidden');
                 this.label.innerHTML = this.labelAttribute;
               }
               else {
                 this.label.setAttribute('hidden','hidden');
               }
             }
             break;
           case 'min':
             this.minAttribute = newValue;
             if(this.number) this.number.setAttribute('min', this.minAttribute);
             if(this.range) this.range.setAttribute('min', this.minAttribute);
             break;
           case 'max':
             this.maxAttribute = newValue;
             if(this.number) this.number.setAttribute('max', this.maxAttribute);
             if(this.range) this.range.setAttribute('max', this.maxAttribute);
             break;
           case 'step':
             this.stepAttribute = newValue;
             if(this.number) this.number.setAttribute('step', this.stepAttribute);
             if(this.range) this.range.setAttribute('step', this.stepAttribute);
             break;
           case 'value':
             this.currentValue = newValue;
             this.valueAttribute = newValue;
             if(this.number) this.number.setAttribute('value', this.valueAttribute);
             if(this.range) this.range.setAttribute('value', this.valueAttribute);
             this.internals.setFormValue(this.currentValue);
             break;
         }
       }
       // Setter und Getter für value.
       set value(value) {
         this.currentValue = value;
         this.number.value = value;
         this.range.value = value;
         this.internals.setFormValue(value);
       }
       get value() {
         return this.currentValue;
       }
     } );   

</script>

<style> self-slider::part(label) { display: block; } self-slider::part(number) { width: 3em; text-align: right;} self-slider::part(range) { width: 10em; } self-slider::part(fieldset) { border: none; }

     body {
       max-width: 50em;
       min-width: 50em;
       --border-color: blue;
       --margin-color: red;
       --padding-color: green;
       --border: 10px;
       --margin: 20px;
       --padding: 5px;
       --border-block-start: 10px;
       --border-block-end: 10px;
       --border-inline-start: 10px;
       --border-inline-end: 10px;
       --margin-block-start: 20px;
       --margin-block-end: 20px;
       --margin-inline-start: 20px;
       --margin-inline-end: 20px;
       --padding-block-start: 5px;
       --padding-block-end: 5px;
       --padding-inline-start: 5px;
       --padding-inline-end: 5px;
     } 
     #border { color: var(--border-color); }
     #margin { color: var(--margin-color); }
     #padding { color: var(--padding-color); }
     #border, #margin, #padding { display: inline-block; }
     fieldset { width: fit-content; }
     
     output { 
       display: inline-block;
       vertical-align: top;
     }
     output > div { 
       background-color: var(--margin-color);
       width: fit-content;
       padding: 0;
       display: inline-block;
     }
     output > div > div { 
       background-color: var(--padding-color);
       width: 200px; height: 200px;
     }
     output.einfach > div > div {
       border: var(--border) solid var(--border-color);
       margin: var(--margin);
       padding: var(--padding);
     }
     output.vollstaendig > div > div {
       border-block-start: var(--border-block-start) solid var(--border-color);
       border-block-end: var(--border-block-end) solid var(--border-color);
       border-inline-start: var(--border-inline-start) solid var(--border-color);
       border-inline-end: var(--border-inline-end) solid var(--border-color);
       margin-block-start: var(--margin-block-start);
       margin-block-end: var(--margin-block-end);
       margin-inline-start: var(--margin-inline-start);
       margin-inline-end: var(--margin-inline-end);
       padding-block-start: var(--padding-block-start);
       padding-block-end: var(--padding-block-end);
       padding-inline-start: var(--padding-inline-start);
       padding-inline-end: var(--padding-inline-end);
     }
     output > div > div > div {
       background-color: white;
       width: 100%;
       height: 100%;
     }
     output:nth-of-type(odd) > div > div { box-sizing: content-box; }
     output:nth-of-type(even) > div > div { box-sizing: border-box; }

</style>

<script> "use strict"

     document.addEventListener("DOMContentLoaded", () => {
       document.body.addEventListener("input", (inputEvent) => {
         document.body.style.setProperty(`--${inputEvent.target.id}`,`${inputEvent.target.value}px`);
       });
     });

</script>

</head>

<body>

Boxmodell

Einfach

   <fieldset>
     <self-slider id="margin" label="Margin" min="0" max="30" value="20" step="1"></self-slider>

<self-slider id="border" label="Border" min="0" max="30" value="10" step="1"></self-slider> <self-slider id="padding" label="Padding" min="0" max="30" value="5" step="1"></self-slider>

    </fieldset>
   <output class="einfach">

box-sizing: content-box

   </output>
   <output class="einfach">

box-sizing: border-box

   </output>


Vollständig

   <fieldset id="margin">
     <legend>Margin</legend>
     <self-slider id="margin-block-start" label="block-start" min="0" max="30" value="20" step="1"></self-slider>
     <self-slider id="margin-block-end" label="block-end" min="0" max="30" value="20" step="1"></self-slider>
     <self-slider id="margin-inline-start" label="inline-start" min="0" max="30" value="20" step="1"></self-slider>
     <self-slider id="margin-inline-end" label="inline-end" min="0" max="30" value="20" step="1"></self-slider>
   </fieldset>
   <fieldset id="border">
     <legend>Border</legend>
     <self-slider id="border-block-start" label="block-start" min="0" max="30" value="10" step="1"></self-slider>
     <self-slider id="border-block-end" label="block-end" min="0" max="30" value="10" step="1"></self-slider>
     <self-slider id="border-inline-start" label="inline-start" min="0" max="30" value="10" step="1"></self-slider>
     <self-slider id="border-inline-end" label="inline-end" min="0" max="30" value="10" step="1"></self-slider>
   </fieldset>
   <fieldset id="padding">
     <legend>Padding</legend>
     <self-slider id="padding-block-start" label="block-start" min="0" max="30" value="5" step="1"></self-slider>
     <self-slider id="padding-block-end" label="block-end" min="0" max="30" value="5" step="1"></self-slider>
     <self-slider id="padding-inline-start" label="inline-start" min="0" max="30" value="5" step="1"></self-slider>
     <self-slider id="padding-inline-end" label="inline-end" min="0" max="30" value="5" step="1"></self-slider>
   </fieldset>


   <output class="vollstaendig">

box-sizing: content-box

   </output>
   
   <output class="vollstaendig">

box-sizing: border-box

   </output>
   

</body> </html>