Jeder kennt es. Wenn Elemente keine feste Höhe haben, geht nur die Transform Funktion. Aber wenn man Abstände einhalten will, gibt es keine CSS Lösung. Hierfür kann man aber einen sehr innovativen JS verwenden
Elemente per JS um X% nach oben verschieben
Mit einem einfachen JS Script, den man ganz einfach in sein Projekt implementieren kann, können wir die Elemente um z.B. 50% verschieben - und das egal wie hoch es ist:
function updateDynamicMargins() {
if (document.querySelectorAll('.dynamic-margin')) {
const elements = document.querySelectorAll('.dynamic-margin');
elements.forEach(element => {
const height = element.offsetHeight;
let offset = 50; // Default offset in percentage
// Check if data-offset attribute exists and is a valid integer
if (element.hasAttribute('data-offset')) {
const dataOffset = parseInt(element.getAttribute('data-offset'), 10);
if (!isNaN(dataOffset)) {
offset = dataOffset;
}
}
element.style.marginTop = `-${(height * offset) / 100}px`;
//console.log('Applying offset ' + offset + '% to height ' + height);
});
}
}
Diese Funktion erwartet ein Element mit der Klasse ".dynamic-margin". Standardmäßg wird jetzt beim Aufruf der Seite einmal nach allen Elementen mit der Klasse gesucht und mit einem margin-top die Hälfte der Element Höhe eingestellt. Wenn man einem Element jetzt noch data-offset hinzufügt, kann man selbst bestimmen um wie viel Prozent das Element nach oben geschoben werden soll.
Hier ein kleines Beispiel, indem ein dynamisch hohes Element um 60% nach oben verschoben wird, ohne das nach unten ein Abstand (Wie bei Translate) kommt:
<div class="col-12 text-area">
<div class="textbox dynamic-margin" data-offset="60">
test
</div>
</div>
Viewports berücksichtigen
Damit die JS Funktion auch beim Viewport-Wechsel funktioniert, und beim Laden der Seite einmal die Margins setzt, müssen noch die folgenden Funktionen eingebunden werden:
document.addEventListener('DOMContentLoaded', function() {
updateDynamicMargins();
}
window.addEventListener('resize', () => {
updateDynamicMargins();
});
Jetzt wird die oben genannte Funktion einmal pro Seitenaufruf, und immer wenn die Größe des Viewports geändert wird aufgerufen.
Nun kann man ganz einfach nur noch im HTML die Klasse für das Element setzen und (Wenn gewünscht) mit dem data-offset den Offset, um wie viel % sich das Element nach oben verschieben soll nutzen. Lässt man data-offset leer, bleibt der Script bei 50%.
Ergebnis
Update: Mobile/Tablet berücksichtigen
Vor Allem bei Mehrspaltigen Elementen, will man diesen Effekt in mobilen Ansichten meist verhindern, wenn es mehrere Elemente sind. Deshalb habe ich nochmal den Script etwas angepasst. Man kann jetzt im HTML noch zwei weitere Klassen hinzufügen, die dann berücksichtigen, ob die Funktion auch Mobil (Oder am Tablet) ausgeführt werden soll:
<div class="row justify-content-sm-center">
<div class="col-12 col-md-6">
<figure class="image dynamic-margin"></figure>
</div>
<div class="col-12 col-md-6">
<figure class="image dynamic-margin ignore-md"></figure>
</div>
</div>
Hier wollen wir in der MD Ansicht, dass das 2. Element nicht mehr den dynamic-margin Effekt hat. Sonst würde das Bild 2 über den Inhalt vom Bild 1 springen
Und hier dazu der angepasste Script:
//dynamic height margin:
function updateDynamicMargins() {
if (document.querySelectorAll('.dynamic-margin')) {
const elements = document.querySelectorAll('.dynamic-margin');
const isMD = window.matchMedia("(max-width: 991px)").matches;
const isMobile = window.matchMedia("(max-width: 766px)").matches;
elements.forEach(element => {
// Check if element should be ignored on tablets
if (isMD && element.classList.contains('ignore-md')) {
element.style.marginTop = '0px'; // Reset margin for ignored elements
return;
}
if (isMobile && element.classList.contains('ignore-mobile')) {
element.style.marginTop = '0px'; // Reset margin for ignored elements
return;
}
const height = element.offsetHeight;
let offset = 50; // Default offset in percentage
// Check if data-offset attribute exists and is a valid integer
if (element.hasAttribute('data-offset')) {
const dataOffset = parseInt(element.getAttribute('data-offset'), 10);
if (!isNaN(dataOffset)) {
offset = dataOffset;
}
}
element.style.marginTop = `-${(height * offset) / 100}px`;
//console.log('Applying offset ' + offset + '% to height ' + height);
});
}
}