Beispiel:BMI-Rechner.html
<!DOCTYPE html> <html lang="de"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>BMI-Rechner</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: 4em; text-align: right;} self-slider::part(range) { width: 20em; } self-slider::part(fieldset) { border: none; }
meter { width: 20rem; }
.safari {
.extreme {
-webkit-appearance: none;
appearance: none;
box-sizing: border-box
}
.extreme::-webkit-meter-suboptimum-value {
background: red;
border-radius: 14px;
}
.extreme::-webkit-meter-bar {
background: rgb(232 232 232);
border-radius: 14px;
height: 14px;
margin-top: 1px;
}
}
.firefox {
.extreme {
appearance: none; /* Firefox */
border: 1px solid #888;
border-radius: 12px;
background: rgb(232 232 232);
height: 12px;
position: relative;
top: -2px;
box-sizing: border-box;
}
.extreme::-moz-meter-bar {
background: red;
border-top-left-radius: 12px; ;
border-bottom-left-radius: 12px; ;
height: 12px;
}
}
.chrome, .egde {
.extreme::-webkit-meter-suboptimum-value {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
.extreme::-webkit-meter-suboptimum-value {
background: red;
}
p { max-width: 30em;}
</style>
<script> "use strict"
// Browser-Check // Source - https://stackoverflow.com/a/52445821 // Posted by Christopher Martin // Retrieved 2026-07-17, License - CC BY-SA 4.0 // Modified by selfhtml
function checkBrowser() {
if(navigator.vendor.match(/google/i)) {
document.body.classList.add("chrome");
}
else if(navigator.vendor.match(/apple/i)) {
document.body.classList.add("safari");
}
else if(navigator.userAgent.match(/firefox\//i)) {
document.body.classList.add("firefox");
}
else if(navigator.userAgent.match(/edge\//i)) {
document.body.classList.add("edge");
}
}
document.addEventListener('DOMContentLoaded', () => {
checkBrowser();
const weight_in = document.querySelector("#weight_in"); const height_in = document.querySelector("#height_in"); const weight_out = document.querySelector("#weight_out"); const height_out = document.querySelector("#height_out"); const bmi_out = document.querySelector("#bmi_out"); const bmi_meter = document.querySelector("#bmi_meter"); const category_out = document.querySelector("#category_out");
document.body.addEventListener("input", (input_event) => { calc_bmi(); });
calc_bmi();
});
function calc_bmi() { let weight = Number(weight_in.value); let height = Number(height_in.value); let bmi = weight / Math.pow(height,2);
let category;
if (bmi <17 ) {
category = "Du hast Magersucht.";
bmi_meter.classList.add("extreme");
}
else if (bmi < 20) {
category = "Du hast Untergewicht.";
bmi_meter.classList.remove("extreme");
} else if (bmi < 25) {
category = "Du hast Normalgewicht.";
bmi_meter.classList.remove("extreme");
} else if (bmi < 30) {
category = "Du hast Übergewicht.";
bmi_meter.classList.remove("extreme");
} else {
category = "Du bist Fettleibig.";
bmi_meter.classList.add("extreme");
}
weight_out.innerText = weight.toLocaleString( undefined, {minimumFractionDigits: 1, maximumFractionDigits: 1}); height_out.innerText = height.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}); bmi_out.innerText = bmi.toLocaleString(undefined, {minimumFractionDigits: 1, maximumFractionDigits: 1});
bmi_meter.value = bmi;
bmi_meter.innerText = bmi.toLocaleString(undefined, {minimumFractionDigits: 1, maximumFractionDigits: 1});
category_out.innerText = category;
} </script>
</head>
<body>
BMI-Rechner
<self-slider id="weight_in" label="Gewicht in kg" min="40" max="200" value="70" step="0.5"></self-slider>
<self-slider id="height_in" label="Größe in m" min="1.2" max="2.2" value="1.8" step="0.01"></self-slider>
Bei einem Gewicht von <output id="weight_out">--</output> kg und einer Größe von <output id="height_out">--</output> m beträgt der BMI <output id="bmi_out">--</output>.
<meter id="bmi_meter" min="10" low="20" high="25" max="40"">BMI</meter>
<output id="category_out">--</output>
Diese Seite ist ein Beispiel für das Erfassen, Verarbeiten und Anzeigen von Daten. Der Autor besitzt kein medizinisches Fachwissen und die Interpretation der Werte erfolgt nach diversen Quellen aus dem Internet, deren Glaubwürdigkeit nicht geprüft wurde.
</body> </html>