Nehmen wir an, ich würde Ihnen sagen, dass wir die unten stehenden Ergebnisse mit nur einem HTML-Element und jeweils fünf CSS-Eigenschaften erzielen können. Kein SVG, keine Bilder (außer dem background am Root, das nur dazu dient, deutlich zu machen, dass unser einziges HTML-Element einige transparente Teile hat), kein JavaScript. Was würden Sie denken, was das beinhaltet?

Nun, dieser Artikel wird erklären, wie das geht, und dann auch zeigen, wie man Dinge durch Hinzufügen von Animationen unterhaltsam gestaltet.
CSS-ing the Gradient Rays
Der HTML-Code besteht nur aus einem <div>.
<div class='rays'></div>
Im CSS müssen wir die Abmessungen dieses Elements festlegen und ihm einen background geben, damit wir es sehen können. Wir machen es auch rund mit border-radius.
.rays {
width: 80vmin; height: 80vmin;
border-radius: 50%;
background: linear-gradient(#b53, #f90);
}
Und… wir haben bereits vier der fünf Eigenschaften verwendet, um das folgende Ergebnis zu erzielen.
Siehe den Pen von thebabydino (@thebabydino) auf CodePen.
Was ist die fünfte? mask mit einem Wert von repeating-conic-gradient()!
Nehmen wir an, wir wollen 20 Strahlen haben. Das bedeutet, wir müssen $p: 100%/20 des vollen Kreises für einen Strahl und die Lücke danach zuweisen.
Hier halten wir die Lücken zwischen den Strahlen gleich den Strahlen (also .5*$p für einen Strahl oder einen Leerraum), aber wir können beides breiter oder schmaler machen. Wir wollen eine abrupte Änderung nach der Endposition des undurchsichtigen Teils (des Strahls), daher sollte die Startposition für den transparenten Teil (die Lücke) gleich oder kleiner als diese sein. Wenn also die Endposition für den Strahl .5*$p ist, kann die Startposition für die Lücke nicht größer sein. Sie kann jedoch kleiner sein, und das hilft uns, die Dinge einfach zu halten, da wir sie einfach auf Null setzen können.
repeating-conic-gradient() funktioniert (live).$nr: 20; // number of rays
$p: 100%/$nr; // percent of circle allocated to a ray and gap after
.rays {
/* same as before */
mask: repeating-conic-gradient(#000 0% .5*$p, transparent 0% $p);
}
Beachten Sie, dass im Gegensatz zu linearen und radialen Verläufen die Stopp-Positionen für konische Verläufe keine Einheiten haben können. Sie müssen entweder Prozentsätze oder Winkelwerte sein. Das bedeutet, dass die Verwendung von etwas wie transparent 0 $p nicht funktioniert. Wir brauchen transparent 0% $p (oder 0deg anstelle von 0%; es spielt keine Rolle, welche wir wählen, sie kann einfach nicht ohne Einheit sein).

Hier gibt es ein paar Dinge zu beachten, wenn es um die Unterstützung geht.
- Edge unterstützt derzeit keine Maskierung auf HTML-Elementen, obwohl dies als In Development aufgeführt ist und ein Flag dafür (das vorerst nichts bewirkt) bereits in
about:flagsaufgetaucht ist.

Das Flag Enable CSS Masking in Edge. conic-gradient()wird nativ nur von Blink-Browsern hinter dem Flag Experimental Web Platform features unterstützt (das überchrome://flagsoderopera://flagsaktiviert werden kann). Unterstützung kommt auch für Safari, aber bis dahin ist Safari immer noch auf das Polyfill angewiesen, genau wie Firefox (oder Edge, wenn es ab der nächsten Version auch Maskierung unterstützt). Update: Ab Chrome 69 istconic-gradient()nicht mehr hinter einem Flag – es funktioniert jetzt in jedem aktuellen Blink-Browser, unabhängig davon, ob das Flag aktiviert ist oder nicht.

Das Flag Experimental Web Platform features ist in Chrome aktiviert. - WebKit-Browser benötigen für
mask-Eigenschaften bei HTML-Elementen immer noch das Präfix-webkit-. Man könnte denken, das sei kein Problem, da wir das Polyfill verwenden, das ohnehin auf -prefix-free basiert. Wenn wir also das Polyfill verwenden, müssen wir -prefix-free sowieso davor einbinden. Leider ist es etwas komplizierter als das. Das liegt daran, dass -prefix-free über Feature-Erkennung funktioniert, was in diesem Fall fehlschlägt, da alle Browsermaskohne Präfix unterstützen… auf SVG-Elementen! Aber wir verwenden hiermaskauf einem HTML-Element, daher sind wir in der Situation, dass WebKit-Browser das Präfix-webkit-benötigen, -prefix-free es aber nicht hinzufügt. Ich denke also, wir müssen es manuell hinzufügen.$nr: 20; // number of rays $p: 100%/$nr; // percent of circle allocated to a ray and gap after $m: repeating-conic-gradient(#000 0% .5*$p, transparent 0% $p); // mask .rays { /* same as before */ -webkit-mask: $m; mask: $m; }Ich denke, wir könnten auch Autoprefixer verwenden, auch wenn wir -prefix-free sowieso einbinden müssen, aber nur dafür beides zu verwenden, fühlt sich ein wenig wie mit Kanonen auf Spatzen schießen an.
Hinzufügen von Animationen
Eine coole Sache an conic-gradient(), das nativ in Blink-Browsern unterstützt wird, ist, dass wir CSS-Variablen darin verwenden können (das geht nicht, wenn wir das Polyfill verwenden). Und CSS-Variablen können jetzt auch in Blink-Browsern mit ein wenig Houdini-Magie animiert werden (wir benötigen das Flag Experimental Web Platform features dafür, auch wenn wir es für die native conic-gradient()-Unterstützung ab Chrome 69+ nicht mehr benötigen).
Um unseren Code für die Animation vorzubereiten, ändern wir unseren Maskierungsgradienten so, dass er variable Alpha-Werte verwendet.
$m: repeating-conic-gradient(
rgba(#000, var(--a)) 0% .5*$p,
rgba(#000, calc(1 - var(--a))) 0% $p);
Dann registrieren wir die benutzerdefinierte Eigenschaft für die Alpha --a.
CSS.registerProperty({
name: '--a',
syntax: '<number>',
initialValue: 1,
inherits: true
})
Beachten Sie, dass die Spezifikation jetzt verlangt, dass inherits explizit angegeben wird, obwohl es vorher optional war. Wenn also Houdini-Demos, die dies nicht angeben, kaputt sind, ist dies mindestens einer der Gründe dafür.
Und schließlich fügen wir im CSS eine animation hinzu.
.rays {
/* same as before */
animation: a 2s linear infinite alternate;
}
@keyframes a { to { --a: 0 } }
Dies ergibt das folgende Ergebnis.

Meh. Sieht nicht so toll aus. Wir könnten es aber interessanter machen, indem wir mehrere Alpha-Werte verwenden.
$m: repeating-conic-gradient(
rgba(#000, var(--a0)) 0%, rgba(#000, var(--a1)) .5*$p,
rgba(#000, var(--a2)) 0%, rgba(#000, var(--a3)) $p);
Der nächste Schritt ist die Registrierung jeder dieser benutzerdefinierten Eigenschaften.
for(let i = 0; i < 4; i++) {
CSS.registerProperty({
name: `--a${i}`,
syntax: '<number>',
initialValue: 1 - ~~(i/2),
inherits: true
})
}
Und schließlich die Animationen im CSS hinzufügen.
.rays {
/* same as before */
animation: a 2s infinite alternate;
animation-name: a0, a1, a2, a3;
animation-timing-function:
/* easings from easings.net */
cubic-bezier(.57, .05, .67, .19) /* easeInCubic */,
cubic-bezier(.21, .61, .35, 1); /* easeOutCubic */
}
@for $i from 0 to 4 {
@keyframes a#{$i} { to { --a#{$i}: #{floor($i/2)} } }
}
Beachten Sie, dass wir, da wir Werte für benutzerdefinierte Eigenschaften festlegen, die Funktion floor() interpolieren müssen.

Sieht jetzt etwas interessanter aus, aber wir können es sicher noch besser machen?
Versuchen wir, eine CSS-Variable für die Stopp-Position zwischen dem Strahl und der Lücke zu verwenden.
$m: repeating-conic-gradient(#000 0% var(--p), transparent 0% $p);
Dann registrieren wir diese Variable.
CSS.registerProperty({
name: '--p',
syntax: '<percentage>',
initialValue: '0%',
inherits: true
})
Und wir animieren sie im CSS mit einer Keyframe-animation.
.rays {
/* same as before */
animation: p .5s linear infinite alternate
}
@keyframes p { to { --p: #{$p} } }
Das Ergebnis ist in diesem Fall interessanter.

Aber wir können es noch ein bisschen aufpeppen, indem wir das Ganze horizontal spiegeln, bevor jede Iteration, sodass es für die Rückwärts-Iterationen immer gespiegelt ist. Das bedeutet, nicht gespiegelt, wenn --p von 0% auf $p geht, und gespiegelt, wenn --p von $p zurück auf 0% geht.
Die Art und Weise, wie wir ein Element horizontal spiegeln, ist, indem wir ihm eine transform: scalex(-1) geben. Da wir möchten, dass dieser Spiegel effekt am Ende der ersten Iteration angewendet und dann am Ende der zweiten (rückwärtslaufenden) Iteration entfernt wird, wenden wir ihn ebenfalls in einer Keyframe-animation an – in einer mit einer steps()-Timing-Funktion und der doppelten animation-duration.
$t: .5s;
.rays {
/* same as before */
animation: p $t linear infinite alternate,
s 2*$t steps(1) infinite;
}
@keyframes p { to { --p: #{$p} } }
@keyframes s { 50% { transform: scalex(-1); } }
Jetzt haben wir endlich ein Ergebnis, das wirklich ziemlich cool aussieht.

CSS-ing Gradient Rays and Ripples
Um das Ergebnis mit Strahlen und Wellen zu erzielen, müssen wir dem mask einen zweiten Gradienten hinzufügen, diesmal einen repeating-radial-gradient().
repeating-radial-gradient() funktioniert (live).$nr: 20;
$p: 100%/$nr;
$stop-list: #000 0% .5*$p, transparent 0% $p;
$m: repeating-conic-gradient($stop-list),
repeating-radial-gradient(closest-side, $stop-list);
.rays-ripples {
/* same as before */
mask: $m;
}
Leider funktioniert die Verwendung mehrerer Stopp-Positionen nur in Blink-Browsern mit aktiviertem Flag Experimental Web Platform features. Und während das conic-gradient()-Polyfill dies für den repeating-conic-gradient()-Teil in Browsern abdeckt, die CSS-Maskierung auf HTML-Elementen unterstützen, aber keine konischen Gradienten nativ unterstützen (Firefox, Safari, Blink-Browser ohne aktiviertes Flag), behebt nichts das Problem für den repeating-radial-gradient()-Teil in diesen Browsern.
Das bedeutet, wir sind gezwungen, einige Wiederholungen in unserem Code zu haben.
$nr: 20;
$p: 100%/$nr;
$stop-list: #000, #000 .5*$p, transparent 0%, transparent $p;
$m: repeating-conic-gradient($stop-list),
repeating-radial-gradient(closest-side, $stop-list);
.rays-ripples {
/* same as before */
mask: $m;
}
Wir kommen offensichtlich näher, aber wir sind noch nicht ganz da.

Um das gewünschte Ergebnis zu erzielen, müssen wir die Eigenschaft mask-composite verwenden und sie auf exclude setzen.
mask-composite wird derzeit nur in Firefox 53+ unterstützt, obwohl WebKit-Browser eine sehr gute Unterstützung (seit Chrome 1.0 und Safari 4.0) für eine ähnliche nicht standardisierte Eigenschaft, -webkit-mask-composite, haben, die uns für einen Wert von xor das gleiche Ergebnis liefert. Edge soll folgen, wenn es die Maskierung von HTML-Elementen unterstützt. Beachten Sie jedoch, dass Edge sowohl mask-composite als auch -webkit-mask-composite mit den Standardwerten unterstützen wird, obwohl jeder, der -webkit-mask-composite zur Zielgruppenansprache von WebKit-Browsern verwendet, es wahrscheinlich mit den nicht standardmäßigen Werten verwenden wird, da es sonst nicht einmal in WebKit-Browsern funktioniert.
$lyr1: repeating-conic-gradient($stop-list);
$lyr0: repeating-radial-gradient(closest-side, $stop-list);
.xor {
/* same as before */
-webkit-mask: $lyr1, $lyr0;
-webkit-mask-composite: xor;
mask: $lyr1 exclude, $lyr0
}
Beachten Sie, dass das nicht standardmäßige -webkit-mask-composite nicht innerhalb des -webkit-mask-Kurzbefehls verwendet werden kann, so wie wir mask-composite innerhalb des mask-Kurzbefehls für Firefox verwenden.

mask-composite und Chrome 1.0+/Safari 4.0+ mit nicht standardmäßigem -webkit-mask-composite).Wenn Sie denken, dass die Strahlen und die Lücken zwischen den Strahlen in Browsern, die conic-gradient() nicht nativ unterstützen, nicht gleich sind, haben Sie Recht. Dies liegt an einem Problem des Polyfills.
Hinzufügen von Animationen
Da der standardmäßige mask-composite derzeit nur in Firefox funktioniert und Firefox conic-gradient() noch nicht nativ unterstützt, können wir keine CSS-Variablen in repeating-conic-gradient() einfügen (da Firefox für diese immer noch auf das Polyfill zurückfällt und das Polyfill keine Verwendung von CSS-Variablen unterstützt). Aber wir können sie in repeating-radial-gradient() einfügen und selbst wenn wir sie nicht mit CSS-Keyframe-Animationen animieren können, können wir es mit JavaScript tun!
Da wir jetzt CSS-Variablen in repeating-radial-gradient(), aber nicht in repeating-conic-gradient() verwenden (da wir eine bessere Browserunterstützung wünschen und Firefox keine konischen Gradienten nativ unterstützt, sodass es auf das Polyfill zurückfällt, das keine CSS-Variablen verwendet), können wir nicht mehr die gleiche $stop-list für beide Gradientenebenen unserer mask verwenden.
Aber wenn wir unsere mask sowieso ohne eine gemeinsame $stop-list neu schreiben müssen, können wir diese Gelegenheit nutzen, um unterschiedliche Stopp-Positionen für die beiden Gradienten zu verwenden.
// for conic gradient
$nc: 20;
$pc: 100%/$nc;
// for radial gradient
$nr: 10;
$pr: 100%/$nr;
Die CSS-Variable, die wir animieren, ist eine Alpha-Variable --a, genau wie bei der ersten Animation im Fall der Strahlen. Wir führen auch die Variablen --c0 und --c1 ein, da wir hier nicht mehrere Positionen pro Stopp haben können und Wiederholungen so weit wie möglich vermeiden wollen.
$lyr1: repeating-conic-gradient(#000 0% .5*$pc, transparent 0% $pc);
$lyr0: repeating-radial-gradient(closest-side,
var(--c0), var(--c0) .5*$pr,
var(--c1) 0, var(--c1) $pr);
body {
--a: 0;
/* layout, backgrounds and other irrelevant stuff */
}
.xor {
/* same as before */
--c0: #{rgba(#000, var(--a))};
--c1: #{rgba(#000, calc(1 - var(--a)))};
-webkit-mask: $lyr1, $lyr0;
-webkit-mask-composite: xor;
mask: $lyr1 exclude, $lyr0
}
Die Alpha-Variable --a ist diejenige, die wir mit ein wenig Vanilla-JavaScript hin und her animieren (von 0 auf 1 und dann zurück auf 0). Wir beginnen damit, eine Gesamtzahl von Frames NF festzulegen, über die die Animation läuft, einen aktuellen Frame-Index f und eine aktuelle Animationsrichtung dir.
const NF = 50;
let f = 0, dir = 1;
Innerhalb einer update()-Funktion aktualisieren wir den aktuellen Frame-Index f und weisen dann den aktuellen Fortschrittswert (f/NF) der aktuellen Alpha --a zu. Wenn f entweder 0 oder NF erreicht hat, ändern wir die Richtung. Dann wird die update()-Funktion bei der nächsten Aktualisierung erneut aufgerufen.
(function update() {
f += dir;
document.body.style.setProperty('--a', (f/NF).toFixed(2));
if(!(f%NF)) dir *= -1;
requestAnimationFrame(update)
})();
Und das ist alles für das JavaScript! Wir haben jetzt ein animiertes Ergebnis.

linear (Live-Demo, Firefox 53+ mit standardmäßigem mask-composite und Chrome 1.0+/Safari 4.0+ mit nicht standardmäßigem -webkit-mask-composite).Dies ist eine lineare Animation, bei der der Alpha-Wert --a auf den Fortschritt f/NF gesetzt wird. Aber wir können die Timing-Funktion zu etwas anderem ändern, wie in einem früheren Artikel von mir über das Emulieren von CSS-Timing-Funktionen mit JavaScript erklärt.
Wenn wir zum Beispiel eine Timing-Funktion vom Typ ease-in wollen, setzen wir den Alpha-Wert auf easeIn(f/NF) anstelle von nur f/NF, wobei easeIn() Folgendes ist:
function easeIn(k, e = 1.675) {
return Math.pow(k, e)
}
Das Ergebnis bei Verwendung einer ease-in-Timing-Funktion ist in diesem Pen zu sehen (Firefox 53+ mit standardmäßigem mask-composite und Chrome 1.0+/Safari 4.0+ mit nicht standardmäßigem -webkit-mask-composite). Wenn Sie daran interessiert sind, wie wir diese Funktion erhalten haben, wird sie im zuvor verlinkten Artikel über Timing-Funktionen detailliert erklärt.
Der exakt gleiche Ansatz funktioniert für easeOut() oder easeInOut().
function easeOut(k, e = 1.675) {
return 1 - Math.pow(1 - k, e)
};
function easeInOut(k) {
return .5*(Math.sin((k - .5)*Math.PI) + 1)
}
Da wir sowieso JavaScript verwenden, können wir das Ganze interaktiv gestalten, sodass die Animation beispielsweise nur bei Klick/Tippen stattfindet.
Um dies zu tun, fügen wir eine Request-ID-Variable (rID) hinzu, die anfangs null ist, aber dann den von requestAnimationFrame() zurückgegebenen Wert in der update()-Funktion annimmt. Dies ermöglicht es uns, die Animation mit einer stopAni()-Funktion zu stoppen, wann immer wir wollen.
/* same as before */
let rID = null;
function stopAni() {
cancelAnimationFrame(rID);
rID = null
};
function update() {
/* same as before */
if(!(f%NF)) {
stopAni();
return
}
rID = requestAnimationFrame(update)
};
Beim Klicken stoppen wir jede laufende Animation, kehren die Animationsrichtung dir um und rufen die update()-Funktion auf.
addEventListener('click', e => {
if(rID) stopAni();
dir *= -1;
update()
}, false);
Da wir mit dem aktuellen Frame-Index f bei 0 beginnen, möchten wir bei jedem Klick in positiver Richtung, also in Richtung NF, gehen. Und da wir die Richtung bei jedem Klick umkehren, muss der anfängliche Wert für die Richtung jetzt -1 sein, damit er beim ersten Klick zu +1 umgekehrt wird.
Das Ergebnis all dessen ist in diesem interaktiven Pen zu sehen (funktioniert nur in Firefox 53+ mit standardmäßigem mask-composite und Chrome 1.0+/Safari 4.0+ mit nicht standardmäßigem -webkit-mask-composite).
Wir könnten auch eine andere Alpha-Variable für jeden Stopp verwenden, genau wie wir es im Fall der Strahlen getan haben.
$lyr1: repeating-conic-gradient(#000 0% .5*$pc, transparent 0% $pc);
$lyr0: repeating-radial-gradient(closest-side,
rgba(#000, var(--a0)), rgba(#000, var(--a1)) .5*$pr,
rgba(#000, var(--a2)) 0, rgba(#000, var(--a3)) $pr);
Im JavaScript haben wir die Timing-Funktionen ease-in und ease-out.
const TFN = {
'ease-in': function(k, e = 1.675) {
return Math.pow(k, e)
},
'ease-out': function(k, e = 1.675) {
return 1 - Math.pow(1 - k, e)
}
};
In der update()-Funktion besteht der einzige Unterschied zur ersten animierten Demo darin, dass wir nicht nur eine CSS-Variable ändern – wir haben jetzt vier, um die wir uns kümmern müssen: --a0, --a1, --a2, --a3. Wir tun dies innerhalb einer Schleife, wobei wir die ease-in-Funktion für die mit geraden Indizes und die ease-out-Funktion für die anderen verwenden. Für die ersten beiden wird der Fortschritt durch f/NF gegeben, während für die letzten beiden der Fortschritt durch 1 - f/NF gegeben ist. Alles in eine Formel gepackt ergibt das:
(function update() {
f += dir;
for(var i = 0; i < 4; i++) {
let j = ~~(i/2);
document.body.style.setProperty(
`--a${i}`,
TFN[i%2 ? 'ease-out' : 'ease-in'](j + Math.pow(-1, j)*f/NF).toFixed(2)
)
}
if(!(f%NF)) dir *= -1;
requestAnimationFrame(update)
})();
Das Ergebnis ist unten zu sehen.

mask-composite und Chrome 1.0+/Safari 4.0+ mit nicht standardmäßigem -webkit-mask-composite).Genau wie bei konischen Gradienten können wir auch die Stopp-Position zwischen dem undurchsichtigen und dem transparenten Teil des maskierenden radialen Gradienten animieren. Dazu verwenden wir eine CSS-Variable --p für den Fortschritt dieser Stopp-Position.
$lyr1: repeating-conic-gradient(#000 0% .5*$pc, transparent 0% $pc);
$lyr0: repeating-radial-gradient(closest-side,
#000, #000 calc(var(--p)*#{$pr}),
transparent 0, transparent $pr);
Das JavaScript ist fast identisch mit dem der ersten Alpha-Animation, nur dass wir keine Alpha-Variable --a aktualisieren, sondern eine Stopp-Fortschrittsvariable --p, und wir verwenden eine Funktion vom Typ ease-in-out.
/* same as before */
function easeInOut(k) {
return .5*(Math.sin((k - .5)*Math.PI) + 1)
};
(function update() {
f += dir;
document.body.style.setProperty('--p', easeInOut(f/NF).toFixed(2));
/* same as before */
})();

mask-composite und Chrome 1.0+/Safari 4.0+ mit nicht standardmäßigem -webkit-mask-composite).Wir können den Effekt interessanter gestalten, indem wir einen transparent-Streifen vor dem undurchsichtigen Streifen hinzufügen und auch den Fortschritt der Stopp-Position --p0 animieren, wo wir von diesem transparent-Streifen zu dem undurchsichtigen wechseln.
$lyr1: repeating-conic-gradient(#000 0% .5*$pc, transparent 0% $pc);
$lyr0: repeating-radial-gradient(closest-side,
transparent, transparent calc(var(--p0)*#{$pr}),
#000, #000 calc(var(--p1)*#{$pr}),
transparent 0, transparent $pr);
Im JavaScript müssen wir jetzt zwei CSS-Variablen animieren: --p0 und --p1. Wir verwenden eine ease-in-Timing-Funktion für die erste und eine ease-out für die zweite. Wir kehren auch die Animationsrichtung nicht mehr um.
const NF = 120,
TFN = {
'ease-in': function(k, e = 1.675) {
return Math.pow(k, e)
},
'ease-out': function(k, e = 1.675) {
return 1 - Math.pow(1 - k, e)
}
};
let f = 0;
(function update() {
f = (f + 1)%NF;
for(var i = 0; i < 2; i++)
document.body.style.setProperty(`--p${i}`, TFN[i ? 'ease-out' : 'ease-in'](f/NF);
requestAnimationFrame(update)
})();
Dies ergibt ein ziemlich interessantes Ergebnis.

mask-composite und Chrome 1.0+/Safari 4.0+ mit nicht standardmäßigem -webkit-mask-composite).
Das ist großartig, Ana!! Deine Tastenklicks sind aber zu laut. Danke dafür!
Großartig! Warte auf mehr Browserunterstützung.
Habe diese Eigenschaften noch nie gehört, bis ich auf deinen Artikel gestoßen bin, aber die Möglichkeiten, die sie bieten, sind ziemlich aufregend und mächtig! Ich freue mich darauf, diese Eigenschaften im Web zu verwenden und zu sehen, wie sich ihre Unterstützung verbessert.
Großartig, aber…
Mein. Kopf. Tut. Weh.
:-)
Danke! Füge Unterstützung für dies zum CSS HTML Validator hinzu… übrigens funktioniert „transparent 0 $p“.
Wie üblich hast du, Ana, wieder einen bahnbrechenden Artikel verfasst, der mit coolen Beispielen und technischen Daten überquillt und zukünftige Webdesign-Innovatoren inspirieren wird. Die Bedeutung deiner Arbeit und deiner Artikel kann in Zeiten neuer aufkommender Webtechnologien nicht hoch genug eingeschätzt werden. Vielen Dank aufrichtig.