Der Begriff „Mustard Cutting“ im Webdesign stammt von Entwicklern bei der BBC, die unterschiedliche Erlebnisse ihrer Website für verschiedene Browser auf verschiedenen Geräten bereitstellen wollten. Sie versuchten insbesondere, die User Agent-Erkennung zu vermeiden.
Aber heutzutage, da immer mehr User Agents auf die Website zugreifen, wird dies zu einer fruchtlosen Übung.
Stattdessen nutzten sie Feature-Erkennung. Modernizr ist das klassische (tolle) Beispiel dafür, aber auch einzeln zusammengestellte Feature-Tests können für sich allein ziemlich klein und einfach sein. Dies ist die Logik, die die BBC verwendet hat, um zu bestimmen, ob ein Browser den Test bestanden hat oder nicht.
if('querySelector' in document
&& 'localStorage' in window
&& 'addEventListener' in window) {
// bootstrap the javascript application
}
Wenn diese Logik fehlschlug, lud die Website weiterhin das, was sie als Kern-Erlebnis bezeichneten. Wenn die Logik bestand, wurden zusätzliche Ressourcen für ein verbessertes Erlebnis geladen.
Ziemlich cool.
Das Laden zusätzlicher CSS und JavaScript ist ziemlich einfach
Es gibt verschiedene Möglichkeiten, dies zu tun, normalerweise über XHR für die Ressource. Filament Group bietet einige sehr kleine, fokussierte Skripte nur dafür: loadCSS und loadJS.
Das Laden von etwas zusätzlichem HTML über XHR ist ähnlich einfach. Aber…
Es ist zu schwer, ein komplett anderes Dokument clientseitig zu laden
Nehmen wir an, Sie brauchen nicht nur ein bisschen zusätzliches CSS, Skripte oder ein bisschen HTML. Was Sie wollen, ist ein komplett anderes Dokument.
Ihr „Kern-Erlebnis“ und „verbessertes Erlebnis“ sind komplett unterschiedliche Sätze von HTML, CSS und JavaScript. Der Versuch, dies clientseitig zu tun, würde bedeuten, ein sehr einfaches Dokument zu laden und dann zu versuchen, im Wesentlichen nachzubilden, wie der Browser-Parser funktioniert. Zuerst machen Sie den Mustard Cut, dann XHR für die richtige Menge an HTML, die Sie benötigen, und fügen sie dann entweder in den DOM ein oder warten vielleicht, bis Sie das CSS per XHR geladen haben, damit Sie keinen „Flash of Unstyled Document“ bekommen. Dann XHR für alle Skripte und stellen Sie sicher, dass Sie sie in der richtigen Reihenfolge ausführen (schwierig).
Schwer umzusetzen.
Dem Server erlauben, das richtige Dokument basierend auf Mustard-Cutting-Informationen zu servieren
Wenn der Server die Ergebnisse Ihres Mustard-Cuts kennen würde, könnten Sie all diesen Ärger vermeiden und das richtige Dokument sofort bereitstellen.
Das ist der Sinn des clientseitigen Mustard-Cuts: Er kann nur auf dem Client durchgeführt werden. Aber… man könnte diese Daten in einem Cookie speichern, und Cookies können vom Server gelesen werden.
Wenn Sie einen Cookie hätten, auf den Sie zählen könnten, könnten Sie etwas wie das hier im Routing Ihrer Website tun.
<?php
// This is just a fake routing/controller kinda setup.
if (isset($_COOKIE["mustard"])) {
// Enhanced experience
if ($_COOKIE["mustard"] == true) {
include_once("enhanced.php");
// Core experience
} else {
include_once("core.php");
}
// No cookie = core experience
} else {
include_once("core.php");
}
?>
Was passiert aber beim ersten Seitenaufruf?
Das ist der knifflige Teil. Dieser Cookie wird beim ersten Seitenaufruf nicht vorhanden sein. Sie könnten einfach zulassen, dass nachfolgende Seiten das richtige Erlebnis liefern, aber das ist wahrscheinlich nicht akzeptabel.
Hier kommt der kontroverseste Teil: Wenn Sie den Cookie nicht haben, aber feststellen können, dass der Browser ihn unterstützt und er aktiviert ist, laden Sie die Seite neu.
Seite neu laden?! Sie machen Witze?
Völlig berechtigte Fragen: Wie kann ein Neuladen eine gute Benutzererfahrung sein? Sind Neuladungen nicht langsam? Könnte man nicht in einer Neuladeschleife gefangen werden?
Ich denke, all diese Dinge können angesprochen werden.
Ganz **oben** im Dokument, wenn der Cookie **nicht** vorhanden ist und der Browser Cookies **unterstützt**.
- Mustard-Cut und speichern Sie die Daten mit JavaScript in einem Cookie
- Wenn die Mustard-Cut-Daten Ihnen sagen, dass Sie ein anderes Dokument laden sollten: Stoppen Sie das Laden/Ausführen der Seite (
window.stop();) und laden Sie neu (location.reload(true);).
Beim Neuladen ist der Cookie für den Server vorhanden.
Wenn dies das erste ist, was ein Dokument tut, geschieht alles so schnell, dass ich es kaum bemerke. Das tun wir für die Editor-Seite auf CodePen, siehe.

Der Trick, um eine Neuladeschleife zu vermeiden, besteht darin, diesen Teil des JavaScript nur auszuführen, wenn Sie sicher sind, dass Cookies unterstützt und aktiviert sind.
Das Mustard-Cutting-Skript
Hier ist ein Mustard-Cut, der nur die Bildschirmbreite testet. Bedenken Sie, dass ein Mustard-Cut alles sein kann, was Sie möchten und was Sie clientseitig testen können.
(function() {
// If the browser supports cookies and they are enabled
if (navigator.cookieEnabled) {
// Set the cookie for 3 days
var date = new Date();
date.setTime(date.getTime() + (3 * 24 * 60 * 60 * 1000));
var expires = "; expires=" + date.toGMTString();
// This is where we're setting the mustard cutting information.
// In this case we're just setting screen width, but it could
// be anything. Think http://modernizr.com/
document.cookie = "screen-width=" + window.outerWidth + expires + "; path=/";
/*
Only refresh if the WRONG template loads.
Since we're defaulting to a small screen,
and we know if this script is running the
cookie wasn't present on this page load,
we should refresh if the screen is wider
than 700.
This needs to be kept in sync with the server
side distinction
*/
if (window.outerWidth > 700) {
// Halt the browser from loading/doing anything else.
window.stop();
// Reload the page, because the cookie will now be
// set and the server can use it.
location.reload(true);
}
}
}());
Tatsächlich **müssen wir dieses Skript gar nicht erst laden**, wenn der Cookie bereits vorhanden ist, da wir wissen, dass die richtige Seite bereits geladen wurde.
<?php
// Run this script as high up the page as you can,
// but only if the cookie isn't already present.
if (isset($_COOKIE["screen-width"]) == 0) { ?>
<script src="mobile-mustard.js"></script>
<?php } ?>
Mögliche Szenarien
- Der normale Erstbesucher: Kein Cookie vorhanden. Das Mustard-Cut-Skript wird ausgeführt und die Seite wird schnell neu geladen. Er erhält das richtige Dokument basierend auf dem Cut.
- Der wiederkehrende Besucher: Cookie ist bereits vorhanden. Er erhält das richtige Dokument basierend auf dem Cut.
- Besucher mit falschem Cookie: Möglicherweise hat er einen Desktop-Browser, der jedoch beim ersten Laden der Seite sehr schmal war, und er hat ihn seitdem verbreitert. Dies kann mit einer CSS @media-Abfrage erkannt werden und es wird ein Link angeboten, um das Problem zu beheben (Demo ansehen).
- Besucher mit ausgeschalteten Cookies: Wir liefern unsere Wahl von Dokumenten. Könnte potenziell falsch sein. Liefern Sie den besten wahrscheinlichen Fall basierend auf den Daten.
- Besucher, bei denen JavaScript nicht ausgeführt wird: Wir liefern unsere Wahl von Dokumenten. Könnte potenziell falsch sein. Liefern Sie den besten wahrscheinlichen Fall basierend auf den Daten.
Mögliche Probleme
Ich sage nicht, dass dies die beste Lösung für dieses Problem ist. Tatsächlich ist es wahrscheinlich besser, wenn Sie alles rein clientseitig erledigen können.
Hier sind einige potenzielle Probleme mit dieser Lösung
- Vielleicht ist das Neuladen langsamer, als ich denke. Ich habe keine Tests mit super alten/super langsamen Geräten durchgeführt, wie ich es wahrscheinlich hätte tun sollen.
- HTML-Caching könnte ein Problem darstellen. Ich habe dies aus erster Hand erlebt, als ich die Demo auf einer Website erstellte, die diese Methode verwendete. Der Server liefert ein gecachtes Dokument, das dann als falsch bestimmt und neu geladen wird, was zu der gefürchteten Neuladeschleife führt. Lösung: Dieses HTML-Dokument nicht cachen oder auf Unterdomänen umleiten basierend auf dem Cut.
- Sicherheitseinstellungen, die den serverseitigen Zugriff auf von JavaScript erstellte Cookies verhindern. Wenn Sie das nicht kontrollieren können, wäre das ein Problem.
Ich verwende diese Technik jedoch in der Produktion und hatte seit Monaten keine Probleme mehr, daher bin ich damit ziemlich zufrieden.
Demo und Repository
Hier ist eine Demo und der Code ist auf GitHub verfügbar, wenn Sie Fehler finden.
Außerdem dachte ich, Client Hints seien hier die Rettung, aber ich bin mir nicht mehr sicher, wo sie in diese Situation passen.
Das Neuladen der Seite ist meiner Meinung nach nicht schnell genug. Viele Male habe ich CodePen besucht und genug von der Benutzeroberfläche gesehen, um meine Maus auf einen Button bewegen zu können… nur um dann unsanft unterbrochen zu werden, als die Seite neu lud. Es wäre eine Sache, wenn der Bildschirm weiß und leer bliebe, während der Test läuft, aber eine voll gestaltete Website zu sehen und sie dann wieder weggenommen zu bekommen, ist nicht gerade toll.
Dies geschieht mit Chrome auf einem vernünftig leistungsfähigen Windows-PC.
Ich würde gerne eine schnelle Screencast bekommen, wenn das möglich ist. Wenn wir von Desktop-Chrome sprechen, sollte es überhaupt nicht neu laden, da wir eigentlich Desktop annehmen und nur auf kleinen Bildschirmen umleiten. Ich bezweifle nicht, dass es passiert, ich brauche nur mehr Informationen, da ich fast jeden Tag an CodePen arbeite und das buchstäblich noch nie gesehen habe.
Ich benutze Chrome Desktop auf einem ziemlich alten Windows-PC und das passiert mir nicht.
Ich halte es für schlecht, Informationen über die Bildschirmbreite in einem langlebigen Cookie zu speichern, da sich diese aufgrund der Geräteausrichtung, Auflösungsänderungen oder angeschlossener externer Monitore zu einem Laptop ändern kann.
Die Demo konfrontiert dieses Problem, indem sie (durch Media Queries) erkennt, ob die falsche Vorlage geladen wurde, und einen Link anbietet, um sie zu korrigieren. Sie könnten sie sogar automatisch korrigieren, wenn Sie wollten, das ist irgendwie die Schönheit von alledem.
Ich nehme an, das GIF zeigt, wie CodePen mobil aussehen soll. Nun, für mich tut es das zumindest nicht. Ich benutze Android 4.2.1 auf einem Smartphone mit hoher Qualität, aber ehrlich gesagt einem fairen Preis (lesen Sie: *chinesisch, aber nicht Apple*) mit einer Auflösung von 1080×1920.
Ich sehe die Desktop-Version die ganze Zeit. Liegt das an der hochauflösenden Anzeige?
Diese 1080er Breite wäre der Grund. Wenn Sie auf diesem Telefon ein `window.outerWidth` vom Browser aus aufrufen, sagt es Ihnen „1080“? Das ist ziemlich breit!
Unser Mustard-Cut bei CodePen ist zugegebenermaßen primitiv. Schreiben Sie diese Technik aber nicht deswegen ab, das ist nur ein einfaches Beispiel. Die Technik tut, was sie tun soll – und Sie können mit dem Mustard-Cut so anspruchsvoll sein, wie Sie möchten.
Danke Chris,.. ich mag diesen Ansatz.. regt zum Nachdenken an. Sind Sie auf SEO/Analytics-bezogene Probleme gestoßen?
Auch wenn Sie es nicht bald/jemals tun werden, wäre es interessant, Ihre Notizen zur Bewertung von progressive enhancement und responsive design für CodePen.io zu sehen.
Was macht die gewünschte Funktionalität und das Erlebnis, das am besten mit dem adaptiven/Mustard-Ansatz hier erreicht wird?
Welche Webtechnologie fehlt, oder was macht ein responsives CodePen.io nicht machbar?
Ich sehe zwei Probleme damit
Welche Version werden Sie Suchmaschinen servieren? Keine Cookies, also nur die „grundlegende“, nehme ich an – wird das ausreichen, damit sie den gesamten Inhalt zum Indexieren erhalten? (Vielleicht könnten wir wieder zur UA-Erkennung für Suchmaschinen-Bots zurückkehren…)
Oder umgekehrt: Könnten sie uns bestrafen, weil wir ihnen die „vollständige“ Version präsentieren – aber dann bestimmten Geräten weniger Inhalte liefern, unter derselben URL?
Ich habe Zweifel an der Zuverlässigkeit, nur `navigator.cookieEnabled` abzufragen und dies als Zeichen zu werten, dass es funktionieren wird. Sie haben bereits „Sicherheitseinstellungen“ erwähnt, die diesbezüglich ein Problem darstellen könnten, aber ich denke, es gibt **viele** potenzielle Szenarien, in denen dies fehlschlagen kann.
Mein Browser hat z. B. eine Einstellung, die mich bei jedem einzelnen Cookie bestätigen lässt – wenn ich das benutze, meldet `navigator.cookieEnabled` true, aber ich kann den Cookie immer noch ablehnen. Außerdem gibt es möglicherweise Firewalls/Proxies, die Cookies von Anfragen an den Server herausfiltern, oder Browser-Erweiterungen, die manipulieren, wie der Browser auf Cookies reagiert oder was `navigator.cookieEnabled` meldet… daher denke ich, dass die Möglichkeit, in einer Weiterleitungsschleife zu landen, sehr real ist. (Ich würde vielleicht zumindest einen Test einbeziehen, der einen gerade gesetzten Cookie-Wert über `document.cookie` zurückliest, um zumindest etwas mehr Sicherheit über den clientseitigen Teil des Problems zu erhalten.)
Sie sagen, Sie hatten „seit Monaten keine Probleme mehr“ – aber würden Sie tatsächlich **wissen**, ob ein Benutzer Ihrer Website Probleme damit hatte? (Ich weiß nicht, auf welche möglichen Maßnahmen oder harten Daten Sie diese Annahme/Schlussfolgerung stützen – ich sage nur, dass keine Beschwerden eingehen nicht unbedingt bedeutet, dass keine Probleme auftreten.)
[Hey, das sah in der Vorschau besser aus – funktioniert Ihr Markdown-Parser wie vorgesehen? Ich habe Zahlen verwendet, um eine Liste mit zwei Elementen zu erstellen, aber sie ist verschwunden…]
Analytics würde hier mehr eine Rolle spielen, aber wenn die meisten Benutzer standardmäßig „enhanced.php“ sind (was ich für das CodePen-Publikum annehmen würde), könnten Sie enhanced.php mit einem „nicht überprüften“ Cookie annehmen und eine asynchrone AJAX-Anfrage verwenden, damit die enhanced.php-Benutzer von Anfang an auf dem Weg sind. Nur Core.php-Benutzer würden von diesem Punkt an eine Neuladung erfordern, sobald die asynchrone Anfrage abgeschlossen ist.
Viele Webanwendungen, die ich gesehen habe, machen das mit einer Ladeleiste, während sie die Fähigkeiten des Benutzers ausarbeiten, obwohl ich nie ein großer Fan einer anfänglichen Ladeleiste bei Websites/Apps war.
Letztendlich ist das, was für den Endbenutzer am leistungsfähigsten ist (sowohl tatsächlich als auch wahrgenommen), das Wichtigste. Ich habe ehrlich gesagt nichts auf CodePen bemerkt, also scheint das, was Sie verwenden, gut zu funktionieren!
Vielleicht irre ich mich, aber warum nicht die richtigen Teile mit Ajax ausliefern?
Es ist geradlinig und einfacher…
Und wenn Sie wirklich Leuten ohne JS Dinge zeigen wollen, können Sie ihnen zeigen: a) nur die Dinge, die mit anderen gemeinsam sind, b) legen Sie, was Sie wollen, in ein noscript-Tag (habe ich seit Ewigkeiten nicht mehr benutzt…)
Liege ich falsch?
Ich habe bereits eine Art davon für mich erstellt und es scheint zu funktionieren (Sie können Touch-Ereignisse und Bildschirmgröße verwenden… aber denken Sie an Touch-Event-Probleme und Windows 8 Convertibles)