<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>toscho.design&#187; Browser</title>
	<atom:link href="http://toscho.de/thema/browser/feed/" rel="self" type="application/rss+xml" />
	<link>http://toscho.de</link>
	<description>Redaktion, Druck- und Webdesign aus Halle (Saale)</description>
	<lastBuildDate>Wed, 11 Aug 2010 09:20:27 +0000</lastBuildDate>
	<language>de-DE-1901</language>
	<sy:updatePeriod>daily</sy:updatePeriod>
	<sy:updateFrequency>4</sy:updateFrequency>
	
		<item>
		<title>Browser-ABC</title>
		<link>http://toscho.de/2010/browser-abc/</link>
		<comments>http://toscho.de/2010/browser-abc/#comments</comments>
		<pubDate>Sun, 16 May 2010 06:35:03 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[Links]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1680</guid>
		<description><![CDATA[Welche Seiten mir der Browser anbietet, wenn ich nur einen Buchstaben in das Adressfeld eintippe.]]></description>
			<content:encoded><![CDATA[<p>Ich bin gerade erst darüber gestolpert – Sonntagmorgen, fragt nicht! – <a href="http://leumund.ch/browser-abc-008247">Christian Leu listet auf</a>, welche Seite ihm der Browser für jeden einzelnen Buchstaben vorschlägt. Find’ ich lustig, also steige ich verspätet noch ein. Das Ergebnis entlarvt mich vermutlich als langweiligen Fachmenschen. Und doch stehe ich dazu.</p>
<p class="wideimg"><img src="http://toscho.de/wp-content/uploads/2010/05/browser-abc.png" alt="Browser-ABC" width="500" height="347" class="size-full wp-image-1681 border" /></p>
<ul>
<li><a href="http://www.andrewnacin.com/">andrewnacin.com</a></li>
<li><a href="http://bugs.webkit.org/">bugs.webkit.org</a></li>
<li><a href="http://core.trac.wordpress.org/">core.trac.wordpress.org</a></li>
<li><a href="http://developer.palm.com/">developer.palm.com</a></li>
<li><a href="http://www.evalotta.net/">evalotta.net</a></li>
<li><a href="http://www.fileformat.info/">fileformat.info</a></li>
<li><a href="https://github.com/">github.com</a></li>
<li><a href="http://hakre.wordpress.com">hakre.wordpress.com</a></li>
<li><a href="http://ip-lookup.net">ip-lookup.net</a></li>
<li><a href="http://www.joindiaspora.com/">joindiaspora.com</a></li>
<li><a href="http://kaliban.de/">kaliban.de</a></li>
<li><a href="http://labjs.com/">labjs.com</a></li>
<li><a href="http://meta.stackexchange.com">meta.stackexchange.com</a></li>
<li><a href="http://neuralmesh.com/">neuralmesh.com</a></li>
<li><a href="http://opera-info.de">opera-info.de</a></li>
<li><a href="http://www.php.net/">php.net</a></li>
<li><a href="http://www.quirksmode.org">quirksmode.org</a></li>
<li><a href="http://research.swtch.com/">research.swtch.com</a></li>
<li><a href="http://stackoverflow.com">stackoverflow.com</a></li>
<li><a href="http://www.typolexikon.de">typolexikon.de</a></li>
<li><a href="http://www.unwrongest.com/">unwrongest.com</a></li>
<li><a href="http://validator.nu">validator.nu</a></li>
<li><a href="http://wpdocs.labs.thedextrousweb.com/">wpdocs.labs.thedextrousweb.com</a></li>
<li><a href="http://xhtmlforum.de">xhtmlforum.de</a></li>
<li><a href="http://yoast.com">yoast.com</a></li>
<li><a href="http://zomigi.com/">zomigi.com</a></li>
</ul>
<p>Wer spielt mit?</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/browser-abc/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Opera: Der Colorpicker</title>
		<link>http://toscho.de/2010/opera-colorpicker/</link>
		<comments>http://toscho.de/2010/opera-colorpicker/#comments</comments>
		<pubDate>Tue, 04 May 2010 21:20:35 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[Opera]]></category>
		<category><![CDATA[Plugin]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1673</guid>
		<description><![CDATA[Ausführliche Vorstellung des Farbwählers in Opera Dragonfly. Screenshots und eine Schritt-für-Schritt-Anleitung.]]></description>
			<content:encoded><![CDATA[<p>Seltsamerweise ist bei all der Presse um Opera 10.5 ein Detail nahezu untergegangen, über das <em>ich</em> mich sehr gefreut habe: Der Farbwähler in Opera <a href="http://www.opera.com/dragonfly/">Dragonfly</a>.</p>
<p><a href="http://toscho.de/wp-content/uploads/2010/05/colorpicker.png"><img src="http://toscho.de/wp-content/uploads/2010/05/colorpicker-300x106.png" alt="Opera Colorpicker" width="300" height="106" class="alignnone size-medium wp-image-1674 border" /></a></p>
<p>Wir finden ihn im Reiter <i lang="en">Utilities</i> in Dragonfly, das wir bei ausgeblendeter Menuleiste am leichtesten erreichen, wenn wir irgendwo im Dokument das Kontextmenu aufrufen und dort ›Element untersuchen‹ auswählen (im Englischen <i lang="en">›Inspect Element‹</i>).</p>
<p>Fahren wir jetzt mit der Maus über die Seite, so wird in einem Vorschaufenster die Fläche unter der Maus stark vergrößert dargestellt.</p>
<p><img src="http://toscho.de/wp-content/uploads/2010/05/colorpicker-auswahlfeld.png" alt="Colorpicker Auswahlfeld" width="278" height="286" class="alignright size-full wp-image-1675 border" />Ganz links können wir festlegen, wie groß die jeweilige Auswahl sein soll, die von der Maus erfaßt wird, und wie stark die Vergrößerung ist.</p>
<p>Das finde ich noch nicht sehr verständlich, und mit <i lang="en">Scale 1</i> fährt sich der Auswahlmodus auch manchmal fest. Mit einem einem kleinen Trick gießen wir Öl ins Getriebe: Kurz den Reiter wechseln; dann läuft es wieder. Langfristig hilft wie bei <em>jedem</em> technischen Problem natürlich nur mehr RAM.</p>
<p><img src="http://toscho.de/wp-content/uploads/2010/05/colorpicker-manage.png" alt="Colorpicker Farbmanager" width="191" height="142" class="alignright size-full wp-image-1676 border" />Auf der linken Fläche finden wir noch ein anderes Feature: Gespeicherte Farben. Hier können wir einmal ausgewählte Farben dauerhaft merken. Der Button <i lang="en">›Manage stored colors‹</i> bietet derzeit nur das Löschen an. Ich wünsche mir noch das Benennen und eine Sortierung nach Schlagworten oder Verzeichnissen. Ansonsten ist das schon sehr praktisch.</p>
<p><img src="http://toscho.de/wp-content/uploads/2010/05/colorpicker-select.png" alt="Colorpicker Select" width="285" height="236" class="alignright size-full wp-image-1677 border" />Rechts des Vorschaufensters können wir innerhalb der Auswahl noch einmal wählen: Wir können ein Quadrat festlegen, das wir mit der Maus auf dem Vorschaufeld plazieren. Der durchschnittliche Farbwert des Quadrates wird dann in drei Notationen ausgegeben: als RGB, als HSL und als Hexwert. Und speichern können wir die Farbe natürlich auch.<br />
Die Maximalgröße des Quadrates beträgt 9×9 Pixel – das finde ich für einige Verläufe und Fotos etwas zu klein. Die Minimalgröße beträgt 1×1 Pixel. Klein genug. Subpixel sieht man ohnehin nicht.</p>
<p>Die Funktionsweise mal Schritt für Schritt zum Mitmachen:</p>
<ol>
<li>Eine Seite öffnen, beispielsweise diese hier.</li>
<li>Rechtsklick auf ein Element (das Auge) und im Kontextmenu ›Element untersuchen‹ auswählen.</li>
<li>Jetzt öffent sich Dragonfly unten im Browserfenster mit dem Reiter ›DOM‹</li>
<li>Zum Reiter ›Utilities‹ wechseln und mit der Maus über das Auge fahren.</li>
<li>Über einer besonders schönen Stelle einmal links klicken, damit das Vorschaubild die Auswahl festhält.</li>
<li>In <i lang="en">Color Select</i> eine Größe wählen (7×7) und im Vorschaubild auf die Stelle klicken, deren durschnittlichen Farbwert man gerne haben möchte.</li>
<li>Wenn der richtige gefunden wurde, auf ›Store color‹ klicken.</li>
<li>Fertig.</li>
</ol>
<p>Brauchen wir später eine gespeicherte Farbe, so klicken wir einfach darauf. Der Wert steht dann im rechten Feld.</p>
<p>Fazit: Die Oberfläche kann durchaus klarer werden, und ein paar Features fehlen mir noch: ein Export und Variieren der Farben beispielsweise. Aber im Ganzen ist das schon eine schöne Demonstration der Möglichkeiten, die die neue API Dragonflys bietet. Dragonfly ist übrigens Open Source, <a href="http://my.opera.com/dragonfly/blog/2010/05/04/100-000-milestone-and-changes-to-the-licence">seit heute</a> unter einer Apache-2.0-Lizenz. Es muß nicht extra installiert werden, womit eine Last wegfällt, die man mit externen Werkzeugen ja meistens hat.</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/opera-colorpicker/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Designlinks 12</title>
		<link>http://toscho.de/2010/designlinks-12/</link>
		<comments>http://toscho.de/2010/designlinks-12/#comments</comments>
		<pubDate>Wed, 28 Apr 2010 10:19:33 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[Zeichen]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1669</guid>
		<description><![CDATA[Eine Katze, die gerne duscht, langsame Referenzen, schlanke User-Agent-Strings, fette Zeichenreferenzen, ein enorm flexibles Stylesheet und ein Malprogramm.]]></description>
			<content:encoded><![CDATA[<p>Wird mal wieder Zeit. Aber zuerst entspannen wir uns ein bißchen:</p>
<p class="wp-caption-text"><object type="application/x-shockwave-flash" data="http://www.collegehumor.com/moogaloop/moogaloop.swf?clip_id=1920326&#038;fullscreen=1" width="480" height="360" ><param name="allowfullscreen" value="true"/><param name="wmode" value="transparent"/><param name="allowScriptAccess" value="always"/><param name="movie" quality="best" value="http://www.collegehumor.com/moogaloop/moogaloop.swf?clip_id=1920326&#038;fullscreen=1"/><embed src="http://www.collegehumor.com/moogaloop/moogaloop.swf?clip_id=1920326&#038;fullscreen=1" type="application/x-shockwave-flash" wmode="transparent"  width="480" height="360"  allowScriptAccess="always"></embed></object><br />
Quelle: <a href="http://www.collegehumor.com/video:1920326" hreflang="en">CollegeHumor</a>.</p>
<p>›<a href="http://schlueters.de/blog/archives/125-Do-not-use-PHP-references.html" hreflang="en" lang="en">Do not use PHP references</a>‹, empfiehlt Johannes Schlüter, denn Referenzen kosten Tempo, Übersicht und Flexibilität. Ob seiner klaren und verständlichen Darstellung dieses kniffligen Themas möchte ich den Artikel jetzt schon in die Liste der zehn besten dieses Jahres rücken.</p>
<p>Nicholas C. Zakas: <a href="http://www.nczonline.net/blog/2010/01/12/history-of-the-user-agent-string/" hreflang="en" lang="en">History of the user-agent string</a>. Warum die UA-Strings heute oft so sonderbar aussehen. Die neue <a href="http://blogs.msdn.com/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx" hreflang="en">Kennung des IE 9</a> lautet:</p>
<pre class="notranslate">Mozilla/5.0 (compatible, MSIE 9.0; Windows NT 6.1; Trident/5.0)</pre>
<p>Anhängsel irgendwelcher Zusatzsoftware werden nicht mehr eingebaut; damit schrumpft die <a href="http://www.useragentstring.com/_uas_Internet%20Explorer_version_8.0.php" hreflang="en">Liste der möglichen Kennungen</a> gewaltig – was es Proxys erheblich erleichtert, gespeicherte Versionen einer Webseite auszuliefern. Das erklärt Billy Hoffman gut in: ›<a href="http://zoompf.com/blog/2010/03/the-big-performance-improvement-in-ie9-no-one-is-talking-about" hreflang="en" lang="en">The Big Performance Improvement in IE9 No One is Talking About</a>‹. Er rät auch dazu, die <a href="http://toscho.de/2010/gzip-pro-und-kontra/">gzip-komprimierte</a> Version <em>nur noch</em> anhand des Accept-Headers zu versenden und den User-Agent zu ignorieren, damit beispielsweise ein Safari-Nutzer die Version bekommt, die der Firefox-Nutzer zuvor in den Proxy gehievt hat.</p>
<p>Man kann <a href="http://toscho.de/2008/zeichenkodierung-begriffe/#toc-maskierung-entity-und-zeichenreferenz">dezimale Zeichenreferenzen</a> mit beliebig vielen führenden Nullen versehen. So läßt sich das <samp>A</samp> als <code>&amp;#65;</code> schreiben oder als <code>&amp;#000000000000000000000000000000065;</code><br />
›hakre‹ hat mal ausprobiert, wie weit man damit gehen kann: ›<a href="http://hakre.wordpress.com/2010/02/25/html-entity-boundaries-zero-padding/" hreflang="en" lang="en">HTML Entity Boundaries – Zero Padding</a>‹.<br />
Ein Experiment, dessen praktischer Nutzen sicher weit unter seinem Unterhaltungswert liegt. Doch zeigt es, wie weit die Entwickler vorausdenken und wo sie die Grenze ziehen zwischen ›das versuche ich noch‹ und ›das wird zu langsam‹. Wenig überraschend frißt Firefox die meisten Nullen – bis zum Erstickungstod.</p>
<p>Anne van Kesteren hat auch ein Experiment mit gewaltigem Geekpotential hingestellt: <a href="http://annevankesteren.nl/test/contenteditable-style.htm" lang="en">Live style sheet editing!</a><br />
Und da muß ich einfach mal den Quelltext zitieren:</p>
<pre class="notranslate">&lt;!doctype html&gt;
&lt;html&gt;
 &lt;head&gt;
  &lt;title&gt;Live style sheet editing!&lt;/title&gt;
  &lt;style style="<code class="string">white-space:pre <i>/* hack for Opera */</i></code>" contenteditable=""&gt;
html {
margin:.2em;
font-size:2em;
color:lime;
background:purple
}
head, title, style
{
display:block
}
body {
display:none
}
  &lt;/style&gt;
 &lt;/head&gt;
 &lt;body&gt;<i>&lt;!-- nothing is needed here --&gt;</i>&lt;/body&gt;
&lt;/html&gt;</pre>
<p>Zum Schluß noch ein Link für die Freunde der Maus: <a href="http://mrdoob.com/projects/harmony/">Harmony</a>, ein Zeichenprogramm in Javascript und Canvas. Das macht wirklich Freude.</p>
<p><img src="http://toscho.de/wp-content/uploads/2010/04/harmony-toscho.png" alt="Harmony. Ein Experiment." width="485" height="330" class="alignnone size-full wp-image-1670 border" /></p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/designlinks-12/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Text-rendering: illegibility</title>
		<link>http://toscho.de/2010/text-rendering-illegibility/</link>
		<comments>http://toscho.de/2010/text-rendering-illegibility/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 05:11:26 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Typographie]]></category>
		<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1665</guid>
		<description><![CDATA[Der Browser des Palm OS stolpert über eine ganz harmlos wirkende CSS-Deklaration – und zeigt dann keinen Text mehr an. Wie man das testet und repariert, zeigt dieser Artikel.]]></description>
			<content:encoded><![CDATA[<p>Wenn zwischen Absicht und Ergebnis fremder Code steht, dann braucht der geübte Binärschubser seine wichtigste Kompetenz: Fluchen. So auch ich, als ich gestern von Christoph Schnieder dieses kleine Horrorstück zugesandt bekam:</p>
<p><img src="http://toscho.de/wp-content/uploads/2010/04/palm-pre-broken.png" alt="palm-pre-broken" width="320" height="480" class="alignnone size-full wp-image-1666" /></p>
<p>Tatort war ein Palm Pre WebOS, Tatwerkzeug der eingebaute Browser auf WebKit-Basis.</p>
<p>Um das überhaupt nachzuvollziehen, habe ich den <a href="http://www.genuitec.com/mobile/" hreflang="en">MobiOne Emulator für Palm Pre</a> installiert. Das ging verdächtig leicht, und das Ergebnis half mir überhaupt nicht. Es war nämlich in Ordnung:</p>
<p><img src="http://toscho.de/wp-content/uploads/2010/04/mobi-one-emulator.png" alt="mobi-one-emulator" width="404" height="758" class="alignnone size-full wp-image-1667" /> </p>
<p>Dieser Emulator ist im Wesentlichen ein zurechtgestutztes Eclipse; seine Abhängigkeit vom Gastsystem erkennt man schon daran, daß er dessen Schriften benutzt. Unbrauchbar.</p>
<p>Dann habe ich das <a hreflang="en" href="http://developer.palm.com/index.php?option=com_content&#038;view=article&#038;layout=page&#038;id=1661">Palm webOS SDK</a> installiert, das in einer virtuellen Maschine läuft – und das Problem ganz genau wiedergibt. Das scheint also ein recht realistisch arbeitendes Werkzeug zu sein. Etwas umständlich finde ich nur das <a href="http://www.uni-regensburg.de/EDV/Misc/KeyBoards/keys02.jpg">englische Tastaturlayout</a>, das ich nicht umstellen konnte.</p>
<p>Nach allerlei Tests habe ich endlich die Ursache gefunden: Ich hatte im Stylesheet eine Deklaration stehen, von der ich annahm, sie werde <a href="https://developer.mozilla.org/En/CSS/Text-rendering" hreflang="en">nur von Gecko interpretiert</a>.</p>
<pre class="notranslate">p,
address,
li
    {
        text-rendering:optimizeLegibility;
    }</pre>
<p>Diese Eigenschaft <a href="http://www.w3.org/TR/SVG/painting.html#TextRenderingProperty" hreflang="en">stammt aus SVG</a>, wie man leicht an der dämlichen Binnenmajuskel erkennt. Sie sollte Firefox dazu anregen, auch bei kleineren Schriftgraden als 20px das <a href="http://www.typolexikon.de/k/kerning.html">Kerning</a> zu respektieren.<br />
Was genau der Palm Browser hier versucht, vermag ich nicht zu sagen. Vielleicht hängt es mit der Schriftgröße zusammen, denn Überschriften, die mindestens 20px groß sind, werden noch gezeigt.</p>
<p>Ich habe die ganze Regel jetzt weggeworfen und einen Bugreport geschrieben.</p>
<p>Sicher ließe sich das auch hinter einem proprietären Selektor für Mozilla verstecken, aber davon will ich eigentlich weg. Und wenn ich damit leben kann, daß Mozilla-Nutzer noch keine abgerundeten Ecken sehen, dann darf ich genauso gut unterstellen, daß sie sich an schlampiges Kerning gewöhnt haben. Also nehmt es mir nicht übel, ja?</p>
<p>Ach ja, das aktuelle Ergebnis:</p>
<p><img src="http://toscho.de/wp-content/uploads/2010/04/palm-web-os-sdk-fixed.png" alt="palm-web-os-sdk repariert" width="319" height="480" class="alignnone size-full wp-image-1668" /></p>
<p>Da der Browser jetzt nur die Systemschriften des Palm OS verwendet, setzt er keine Kursivschnitte für serifenlose Schriften mehr um, und eine Monospace-Schrift findet oder nutzt er auch nicht. Das ist nicht schlimm, aber man kann es unter »Aha. Mist!« ablegen.</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/text-rendering-illegibility/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Webdesign fürs iPad</title>
		<link>http://toscho.de/2010/webdesign-fuers-ipad/</link>
		<comments>http://toscho.de/2010/webdesign-fuers-ipad/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 13:43:33 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1625</guid>
		<description><![CDATA[Wie man sein Layout iPad-tauglich gestaltet.]]></description>
			<content:encoded><![CDATA[<p>Der Bettvorleger ist <a href="http://www.heise.de/mobil/meldung/iPad-Apple-praesentiert-das-erwartete-Tablet-2-Update-915500.html">gelandet</a>. Apple hat am Mittwoch das iPad vorgestellt, ein Gerät, das die Nachteile eines Notebooks mit denen des iPhones kombiniert: Kein USB-Anschluß, kein DVD- oder BlueRay-Laufwerk, kein UMTS. Multitasking, das Ausführen parallel laufender Programme, geht auch nicht. Das einzige, das glänzt, ist das Display in einer Auflösung von 768×1024 Pixeln.</p>
<p><object width="480" height="295"><param name="movie" value="http://www.youtube.com/v/1ZS8HqOGTbA&#038;hl=de_DE&#038;fs=1&#038;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/1ZS8HqOGTbA&#038;hl=de_DE&#038;fs=1&#038;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="295"></embed></object></p>
<p>Viele <a title="Christian Reber: iPad - Aber auch nur beinahe perfekt" href="http://www.christianreber.com/ipad-aber-auch-nur-beinahe-perfekt">Beobachter</a> geben sich jetzt <a href="http://al3x.net/2010/01/28/ipad.html" hreflang="en" title="Alex Payne: On the iPad">enttäuscht</a>. So ein Wirbel um ein so <em>langweiliges</em> Spielzeug? Mich hat das nicht überrascht oder gar enttäuscht. Ich mache mit Apple ohnehin keine Geschäfte.<br />
Aber für den Markt freue ich mich: Die Geräteklasse wird durch Apple eingeführt und bekannt gemacht, und jeder Konkurrent kann den Pionier leicht ausstechen. Es genügt ein USB-Anschluß und die Option, daß der Kunde im Gegensatz zum iPad seine Akkus <em>selber wechseln</em> kann, wenn er möchte. Packt man noch ein richtiges, <em>mattes</em> Display drauf und eine UMTS-Verbindung, dann kommt sogar ein mobiles Gerät dabei heraus.</p>
<p>Als Designer freue ich mich auch: Die Bildschirmbreite von maximal 1024 Pixeln wird all jenen auf die Füße fallen, die bisher Festbreiten gemeißelt und damit das Web verschmutzt haben. Real werden die Benutzer dieses Spielzeugs lieber hochkant lesen, also nur 768 Pixel bereitstellen. Gute Layouts passen sich dem an, schlechte werden einfach nicht mehr benutzt.</p>
<p>Wer jetzt erst auf ein modernes Layout umstellt, mag dies bedenken:</p>
<ul>
<li>Auf einem <i lang="en">Touchscreen</i> sollten <strong>Links</strong> nicht zu dicht beieinander liegen. Finger treffen schlechter als eine Maus. Peter-Paul Koch hat dazu gerade ein bißchen geforscht: <a href="http://www.quirksmode.org/blog/archives/2010/02/the_touch_actio.html" hreflang="en" lang="en">The touch action</a>.<br />
Das interessante Problem hierbei: Wer mit solchen Bildschirmmaßen kommt und <em>doch</em> eine Maus benutzt, der möchte keinen Platz für zusätzlichen Leeraum vergeuden. Vielleicht wird sich der iPad-Safari ja per Javascript zu erkennen geben, damit man den gezielt ansprechen kann.<br />
Die Pseudo-Klasse <code>:hover</code> oder <code>onmouse*</code>-Events werden nicht angesprochen.</li>
<li>Eine horizontale Navigation sollte am Seitenrand <strong>umbrechen</strong>, sonst verschwinden vielleicht wichtige Elemente rechts hinter dem Bildschirmrand.</li>
<li>Bei Tageslicht liefert ein Spiegeldisplay schlechte <strong>Kontraste</strong>. Orangefarbene Links auf weißem Hintergrund beispielsweise dürften kaum noch zu erkennen sein.<br />
Sehr lange Texte möchte sicher niemand auf weißem Hintergrund lesen. Hier kann man einen Styleswitcher anbieten, wenn das iPad keinen eigenen Regler mitbringt.</li>
<li>
<p>Safari, der Webbrowser auf dem iPad, unterstützt <strong><a href='http://www.w3.org/TR/css3-mediaqueries/' hreflang="en" lang="en">Media Queries</a></strong> ein bißchen. Das kann man so ansprechen:</p>
<pre class="notranslate">@media screen and (max-device-width: 1024px)
{
    <em>/* Horizontal */</em>
}
@media screen and (max-device-width: 768px)
{
    <em>/* Vertikal */</em>
}
@media screen and (max-device-width: 480px)
{
    <em>/* iPhone. Findet @media handheld nicht. */</em>
}</pre>
<p>Opera und Firefox verstehen das natürlich auch, im Gegensatz zu Safari sogar nach einer <a hreflang="en" href="http://msdn.microsoft.com/en-us/library/ms537634(VS.85).aspx">IE-Expression</a>.</p>
<pre class="notranslate">* html textarea
    {
        border:             expression(
            this.onfocus = function()
                {
                    this.style.borderColor = '<code class="string">#27b</code>';
                },
            this.onblur = function()
                {
                    this.style.borderColor = '<code class="string">#888</code>';
                }
            );
    }

@media screen and (max-device-width: 768px)
{
    <em>/* Das liest Safari nicht. */</em>
}</pre>
</li>
<li>Auf dem iPad gibt es <strong>kein Flash</strong>. Dafür sollte normalerweise schon längst eine Alternative bereitstehen, aber oft sieht die <a href="http://www.google.com/search?q=ihr+browser+unterst%C3%BCtzt+kein+flash&#038;num=50&#038;ie=utf-8&#038;oe=utf-8">eher peinlich</a> aus. Safari versteht Javascript und <a href="http://www.peterkroener.de/eine-kleine-canvas-einfuehrung/">Canvas</a>; wer das nutzt, kann auf Flash oft verzichten.</li>
<li>Wenn der Safari als Mobilvariante installiert ist, dann kann er vielleicht <a href="http://doctyper.com/archives/200808/fixed-positioning-on-mobile-safari/">kein <code>position:fixed</code></a>.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/webdesign-fuers-ipad/feed/</wfw:commentRss>
		<slash:comments>48</slash:comments>
		</item>
		<item>
		<title>CSS: Mein Userstylesheet</title>
		<link>http://toscho.de/2010/css-mein-userstylesheet/</link>
		<comments>http://toscho.de/2010/css-mein-userstylesheet/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 12:09:36 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[Opera]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1605</guid>
		<description><![CDATA[Meine derzeit verwendete Universalvorlage.]]></description>
			<content:encoded><![CDATA[<p>CSS habe ich mit Userstylesheets gelernt, und diese Perspektive prägt meine Arbeit noch heute. Mein Standardstylesheet ist seit  <a href="http://www.opera.com/docs/history/#o351" hreflang="en">Opera 3.5</a> lange mit den Fähigkeiten des Browsers <a title="Mein Userstylesheet von 2004" href="http://opera-info.de/forum/thread.php?threadid=739">gewachsen</a>, doch seit etwa zwei Jahren werfe ich immer mehr heraus.</p>
<p>Für bestimmte Webseiten stecke ich mir noch Spezialvorlagen aus einem privaten Framework zusammen. Das Gestalten von Formularen und Scrollbars im Browser habe ich abgeschaltet, und der Adblocker arbeitet zuverlässig. Das aktuelle Userstylesheet sieht deshalb sehr schlank aus:</p>
<pre class="notranslate">*
    {
        letter-spacing:     normal      !important;
    }
body
    {
        line-height:        1.4;
        font-family:        "<code class="string">Minion Web Pro</code>";
        margin:             10px;
    }
@media print
    {
        body
            {
                margin:     0 10%;
            }
    }
p, li, blockquote, dd, dt, div
    {
        font-size:          16px;
        line-height:        1.4;
    }
#content p, #content li, #content blockquote
    {
        font-size:          16px        !important;
        line-height:        1.4         !important;
    }
body,
div,
p,
li,
dl, dt, dd,
td
    {
        cursor:             text        !important;
    }
textarea,
pre, pre *,
code,
.code,
samp,
var,
.dp-highlighter,
.dp-highlighter * <i>/* oft benutztes Highlightscript */</i>
    {
    <i>/* Die Lucida Sans Unicode hilft beim Finden exotischer Zeichen. */</i>
        font:               1em/1.2 Consolas, Lucida Sans Unicode,
                            monospace   !important;
        background-image:   none        !important;
        cursor:             text        !important;
    }
textarea:focus
    {
        color:              #000        !important;
        background:         #fff        !important;
    }
pre *,
code *,
.code *,
samp *,
var *
    {
        font-size:          1em         !important;
    }
pre,
pre *
    {
        line-height:        1.3         !important;
        white-space:        pre-wrap    !important;
    }
[align="justify"]
    {   <i>/* Andere Blocksatzsünder findet man leider nicht so leicht. */</i>
        text-align:         left        !important;
    }
table,
td,
th
    {
        border-collapse:    collapse;
        vertical-align:     top         !important;
    }
a:hover
    {
        text-decoration:    none;
    }
[href],
[onclick]
    {
        cursor:             pointer     !important;
    }
iframe[width="0"], iframe[height="0"],
iframe[width="1"], iframe[height="1"],
img[width="0"], img[height="0"],
img[width="1"], img[height="1"]
    {
        display:            none        !important;
    }
[alt]
    {
        white-space:        normal      !important;
    }
h1[id]:hover:after,
h2[id]:hover:after,
h3[id]:hover:after,
h4[id]:hover:after,
h5[id]:hover:after,
h6[id]:hover:after
    { <i>/* Findet interne Links, falls ich mal auf
       einen Abschnitt in einer Seite linken will. */</i>
        content:            "<code class="string"> #</code>" attr(id);
        font:               bold 14px/1 Consolas;
    }
button,
[type="submit"]
    {
        color:              #000        !important;
    }</pre>
<p>Siehe auch:</p>
<ul>
<li><a href="http://toscho.de/2009/userscript-userstyle-spiegel/">Userscript und Userstyle für Spiegel Online</a></li>
<li><a href="http://toscho.de/2009/licht-aus/">Licht aus! Das dunkle Userstylesheet</a></li>
<li><a href="http://toscho.de/2009/stil-des-stylesheets/">Der Stil des Stylesheets</a></li>
</ul>
<p>Eure Vorschläge?</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/css-mein-userstylesheet/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Designlinks 11</title>
		<link>http://toscho.de/2010/designlinks-11/</link>
		<comments>http://toscho.de/2010/designlinks-11/#comments</comments>
		<pubDate>Sat, 16 Jan 2010 18:13:39 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1588</guid>
		<description><![CDATA[Über den Dialog zwischen Webprofis und Amateuren, eine performante Einbindung von Print-Stylesheets, das Opera-OS »Tabbee« und einen ungewöhnlichen Fall von Unordnung.]]></description>
			<content:encoded><![CDATA[<ul>
<li>Molily: <a lang="en" href="http://molily.de/weblog/new-amateurs">In Defense of New Amateurs</a>.<br />
Laßt euch vom Titel nicht erschrecken: Der Text wurde auf Deutsch geschrieben.<br />
Mathias beklagt hier, daß die Webexperten sich nicht (genug) um die Anfänger kümmerten, zu wenig verständliches Wissen vorhanden sei und kein Dialog zustande komme.</p>
<p>Ich finde es gut und wichtig, diesen Dialog zwischen Profis und Amateuren mal zum Thema zu machen. Aber ganz so schlecht ist die Situation ja nicht: Michael Jendryschik hat mit seiner <a href="http://jendryschik.de/wsdev/einfuehrung/">Einführung in XHTML, CSS und Webdesign</a> einen übersichtlichen Einstieg hingelegt, den man kostenlos im Netz lesen oder als Buch kaufen kann. Im <a href="http://xhtmlforum.de/">XHTML-Forum</a> diskutieren täglich Anfänger und Experten auf Augenhöhe miteinander – zuweilen mit eiserner Geduld.</p>
<p>Und dann gibt es tausende Blogs, kleine Foren und ähnliche Angebote. Die Information für Einsteiger gibt es noch – nur weiter gestreut als vor zehn Jahren.</li>
<li>Billy Hoffman: <a hreflang="en" lang="en" href="http://zoompf.com/blog/2009/12/browser-performance-problem-with-css-print-media-type/">Browser Performance Problem with CSS “print” Media Type</a>.
<p>Webbrowser sind gierig: Sie laden <span lang="en">Print-Stylesheets</span> immer, ob gedruckt wird oder nicht. Hoffman schlägt unter anderem vor, den Link zu diesem Stylesheet erst nach <code>onload</code> ins Dokument zu schreiben, um das Rendering am Bildschirm zu beschleunigen.</p>
<p>Wer dann aber versucht, eine validierende Noscript-Variante einzubauen, dürfte ordentlich ins Schwitzen kommen.</p>
<p>Sehr unschön finde ich übrigens die vielen Spamlinks im Seitenkopf. In Opera mal unter »Ansicht/Seitendarstellung« den Benutzermodus auswählen … und das Essen im Magen halten. Bah!</li>
<li>Haavard K. Moen: <a hreflang="en" lang="en" href="http://my.opera.com/haavard/blog/2009/12/14/opera-tabbee">Chrome OS, eh? How about designing your own OS using Opera and Widgets?</a>.
<p>Haavard stellt <a hreflang="fr" href="http://www.tabbee.fr/">Tabbee</a> vor, die Alternative zu Chrome OS. Die ganze Oberfläche besteht aus Opera-Widgets!<br />
Bei den Auswahllisten sieht man gut, warum man <em>so</em> keine Navigation bauen sollte: Der Finger ist doppelt so dick wie ein Listeneintrag.</p>
<p><object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/k7VhlItPzkE&#038;hl=de_DE&#038;fs=1&#038;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/k7VhlItPzkE&#038;hl=de_DE&#038;fs=1&#038;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></embed></object>
</li>
<li><a hreflang="en" lang="en" href="http://www.sankakucomplex.com/2009/12/29/otaku-nightmare-room/">Otaku Nightmare Room</a>.
<p>Ganz ehrlich: Bei mir sieht es nicht immer ordentlich aus. Die ganze Wohnung ist zugebüchert; selbst unter der Decke habe ich Regale langgezogen. Aber seitdem ich <em>das</em> gesehen habe, fühlt sich meine Wohnung geradezu steril an.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/designlinks-11/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Gzip: Pro und Kontra</title>
		<link>http://toscho.de/2010/gzip-pro-und-kontra/</link>
		<comments>http://toscho.de/2010/gzip-pro-und-kontra/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 16:15:18 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[Suchmaschinen]]></category>
		<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1601</guid>
		<description><![CDATA[Warum gzip nicht nur Probleme löst und wann man sich dafür oder dagegen entscheidet.]]></description>
			<content:encoded><![CDATA[<p>Die Firefox-Addons <a href="https://addons.mozilla.org/de/firefox/addon/5369">YSlow (Yahoo)</a> und <a href="http://code.google.com/intl/de/speed/page-speed/">Page Speed (Google)</a> helfen Webentwicklern, die Ladezeiten ihrer Seiten zu beschleunigen.<br />
Sie arbeiten ihrer Natur nach sehr pauschal und empfehlen immer, alle textbasierten Webressourcen mit <i lang="en">gzip</i> zu komprimieren.</p>
<p><a href="http://www.gzip.org/">Gzip</a> (<abbr title="GNU is not Unix">GNU</abbr> zip) komprimiert Textdateien sehr effizient. Das Format wird nicht durch Patente belastet, und die meisten Browser und Crawler können damit umgehen. Die <em>meisten</em>, nicht <em>alle</em>.</p>
<p>Wir können die komprimierte Variante einer Ressource nicht auf gut Glück verschicken, sondern nur, wenn der Empfänger dies bekannt gibt:</p>
<p><em lang="en">Request-Header:</em></p>
<pre class="notranslate">Accept-Encoding: <strong>deflate</strong>, <strong>gzip</strong>, <strong>x-gzip</strong>, identity, *;q=0</pre>
<p>Das heißt: Wir müssen <i lang="en">Content-Negotiation</i> betreiben, über den Inhalt also mit dem Empfänger verhandeln – und eine unkomprimierte Variante vorhalten. </p>
<p>Spannend finde ich die Erkenntnisse, die Arvind Jain und Jason Glasgow <a href="http://googlecode.blogspot.com/2009/11/use-compression-to-make-web-faster.html">zusammengefaßt</a> haben: Anti-Virus-Software, Browser-Bugs, Webproxys und fehlkonfigurierte Webserver verhindern oft die Kompression.</p>
<p>Nehmen wir einmal an, Browser 1 verstehe gzip, Browser 2 nicht. Beide erreichen unsere Website über den selben Proxyserver. Browser 1 holt sich die gzip-Variante, der Proxy speichert diese und schickt sie später Browser 2. Obwohl der mit gzip nichts anzufangen weiß. Nicht so gut.</p>
<p>Also senden wir das Dokument mit einem Response-Header zurück, der den Proxy darüber informiert, wann er die Seite an einen anderen Browser ausliefern darf: Wenn der das gleiche <i lang="en">Accept-Encoding</i> vorlegt.</p>
<p><em lang="en">Response-Header:</em></p>
<pre class="notranslate">Vary: Accept-Encoding</pre>
<p>Der <i lang="en">Vary-Header</i> wurde erst in HTTP/1.1 eingeführt – also bekommen alle Anfragen, die per HTTP/1.0 einschlagen, <em>immer</em> die unkomprimierte Variante.</p>
<p>Jetzt kann der Internet Explorer (zumindest bis Version 6) die unkomprimierte Ressource überhaupt <a href="http://marc.info/?l=apache-modgzip&#038;m=103951214411428&#038;w=2">nicht mehr</a> im <i lang="en">Cache behalten</i>, und die komprimierte landet auf jeden Fall darin. »Abhilfe« schafft ein weiterer </p>
<p><em lang="en">Response-Header:</em></p>
<pre class="notranslate">Cache-Control: private</pre>
<p>Und jetzt kann der Proxy die Ressource nicht mehr speichern. </p>
<p>Um das Thema »Internet Explorer« schnell hinter uns zu bringen, seien noch zwei Bugs erwähnt: </p>
<ul>
<li>Wenn ein XHTML-Dokument komprimiert und mit XML-Deklaration verschickt wird <em>und</em> überdies sehr lange oder viele Response-Header (Cookies beispielsweise) vorausgehen, dann versucht der Internet Explorer 6 in einigen Versionen, den MIME-Typen zu erraten. Er kommt dann zu dem Schluß, er habe XML vor der Nase – und <a href="http://support.microsoft.com/kb/947195/en-us">scheitert kläglich</a>.</li>
<li>Wenn ein komprimiertes Dokument per SSL (HTTPS) angeboten wird, kann es auch passieren, daß der Leser <a href="http://support.microsoft.com/?scid=kb;en-us;837251&#038;spid=2073&#038;sid=218">gar nichts sieht</a>.</li>
</ul>
<p>Inzwischen hat sich die Situation jedoch <a href="http://blogs.msdn.com/ie/archive/2005/10/31/487509.aspx">gebessert</a>.</p>
<p>Zu den Problemen beim Transfer und beim Caching stellt sich noch die Frage: <em>Lohnt es sich?</em><br />
Das Ein- und Auspacken kostet ja auch Zeit. Gerade bei Dokumenten, die erst bei Abruf komprimiert werden, müssen wir Faktoren berücksichtigen, die eventuell den Zeitgewinn ausstechen: die Serverlast und die Verarbeitungsdauer auf dem Server und beim Client.<br />
Ein 3-kB-Dokument zu komprimieren, bringt überhaupt nichts. Bei 5 kB wird es langsam interessant, und ab 10 kB spürt der Leser den Unterschied.</p>
<p>Wir sollten beide Varianten statisch vorhalten, damit der Server nicht immer wieder dieselbe Arbeit erledigen muß. Hier fällt natürlich noch ein gewisser Koordinationsaufwand an.</p>
<p>Wann also komprimieren?</p>
<ul>
<li>Wenn die Ressource nicht unbedingt im Cache landen soll und/oder</li>
<li>5 kB überschreitet und</li>
<li>der Server genug Kapazität dafür übrig hat oder beide Varianten fertig vorliegen.</li>
</ul>
<p>Und wann nicht?</p>
<ul>
<li>Wenn die Ressource unbedingt in den Cache gelangen soll (Stylesheets in einem Webforum) und noch viele IE-6-Nutzer daherkommen oder</li>
<li>der Server unter hoher Last steht oder</li>
<li>das generierende Skript schon lange genug arbeitet.</li>
</ul>
<p>Diese Hinweise bitte ich als grobe Richtlinien zu verstehen. Je nach Kontext können sie auch sehr danebenliegen. Per <code>@font-face</code> eingebettete Schriften will man <a href="http://www.phpied.com/font-face-gzipping-take-ii/">ganz gewiß komprimieren</a> – aber nur einmal verschicken. Hier lohnt sich ein <a href="http://toscho.de/2010/logfiles-analysieren/">Blick ins Logfile</a>: Welche Browser benutzen meine Leser? Und dann trifft man eine informierte Entscheidung.</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/gzip-pro-und-kontra/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>WordPress: Shortlinks reloaded</title>
		<link>http://toscho.de/2010/wordpress-shortlinks-reloaded/</link>
		<comments>http://toscho.de/2010/wordpress-shortlinks-reloaded/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 21:25:07 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[Interna]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[Markup]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webdesign]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Plugin]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1594</guid>
		<description><![CDATA[Wie man Short-URIs in WordPress erzeugt, ausgibt und narrensicher per .htaccess abfängt. Code und ein Plugin zum Download.]]></description>
			<content:encoded><![CDATA[<!--TOC-->
<p>Im April 2009 habe ich gezeigt, wie man in WordPress <a href="http://toscho.de/2009/shortlinks-in-wordpress/">mit Bordmitteln kurze URLs</a> für Seiten und Artikel erzeugt: Blog-Adresse plus »<code class="string">?p=</code>« plus Post-Id. Das funktioniert einfach und schnell. Nicht.</p>
<h2>Formatkrieg</h2>
<p>Meine Grundidee war: Ich habe nur einen Ort für die Logik des Verfahrens – die <code>functions.php</code>. Das stellte sich als zu naiv heraus, als die ersten <strong>kaputten Crawler</strong> aufschlugen, die das Fragezeichen mit einem <code>urlencode()</code> vorbehandelten. Requests auf <samp>/%3F=762</samp> sind eben etwas anderes als auf <samp>/?=762</samp>.</p>
<p>Jetzt mußte ich doch einen zweiten Ort anfassen: die .htaccess.</p>
<pre class="notranslate">RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/\<strong>%3f</strong>p\=(\d+)$
RewriteRule ^.* /?p=%1 [L,R=301]</pre>
<p>Dann versagte auch die URL-Erkennung bei <strong>Twitter</strong>: Verlinkt wurde nur der Teil bis zum Fragezeichen, alles dahinter fiel weg.<br />
Also habe ich die Kurz-URLs auf das Format /p762 umgestellt und die .htaccess angepaßt:</p>
<pre class="notranslate">RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/\%3fp\=(\d+)$ [OR]
RewriteCond %{REQUEST_URI} ^<strong>/p</strong>\=?(\d+)$
RewriteRule ^.* /?p=%1 [L,R=301]</pre>
<p>Auftritt <strong>Rivva-Bot</strong>: Der hat das neue Format um einen Slash <code>/</code> ergänzt, <a href="http://toscho.de/2010/logfiles-analysieren/#toc-400er">die Fehlerseite bestaunt</a> – und dann blieb er weg. Kein Problem:</p>
<pre class="notranslate">RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/\%3fp\=(\d+)$ [OR]
RewriteCond %{REQUEST_URI} ^/p\=?(\d+)<strong>/?</strong>$
RewriteRule ^.* /?p=%1 [L,R=301]</pre>
<h2>Markup</h2>
<p>In einem sehr fruchtbaren <a href="http://toscho.de/2009/shortlinks-in-wordpress/#comment-405">Ideen-Pingpong</a> (vulgo: Dialog) mit <a href="http://bernhardhaeussner.de/">Bernhard Häussner</a> haben wir die perfekte Notation für die Bekanntgabe des Shortlinks gefunden: Ein separater HTTP-Header samt <code>meta</code>-Element:</p>
<pre class="notranslate">&lt;meta http-equiv="<code class="string">X-Short-URI</code>" content="<code class="string">http://toscho.de/?p=762</code>"&gt;</pre>
<p>Interessiert kein Schwein. Am 14. August <a href="http://en.blog.wordpress.com/2009/08/14/shorten/">schuf WordPress.com Tatsachen</a> und verstetigte die sehr schlechte Lösung <code>rel="shortlink"</code> (<a href="http://microformats.org/wiki/rel-shortlink">Referenz</a>). Schade.</p>
<p>Jetzt könnte die URL also so angegeben werden:</p>
<pre class="notranslate">&lt;link rel="shortlink" href="http://toscho.de/?p=762"&gt;</pre>
<p><div id="attachment_1595" class="wp-caption alignright" style="width: 287px"><img src="http://toscho.de/wp-content/uploads/2010/01/opera-shortlink-info.png" alt="Opera: Shortlink im Infopanel" width="277" height="279" class="border size-full wp-image-1595" /><p class="wp-caption-text">Opera: Shortlink im Infopanel</p></div><em>Könnte.</em> Opera, auf den ich unter keinen Umständen verzichte, ignoriert leider genau diesen Link im Info-Panel. Also füge ich als Beziehung noch ein <code>alternate</code> hinzu, damit die Erkennung wieder klappt.<br />
Wer es ausprobieren möchte: F4 drücken, »Leiste anpassen/Erscheinungsbild/Paneele/« und ein Häkchen bei »Info« setzen.</p>
<h2 style="clear:right">PHP-Code</h2>
<p>Ich habe den Code zur Ausgabe in WordPress in eine kleine Klasse mit statischen Methoden gegossen – des armen Mannes Namensraum. Verzeiht mir.</p>
<pre class="notranslate">&lt;?php
<i>/**
 * Class Short_URI: Short-URIs erzeugen und ausgeben.
 * @author Thomas Scholz &lt;http://toscho.de&gt;
 * @see <a href="http://microformats.org/wiki/rel-shortlink">http://microformats.org/wiki/rel-shortlink</a>
 * @license GPL 3 &lt;<a href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>&gt;
 * @version 1.3
 *
 */</i>
class Short_URI {

    <i>/**
     * Kurz-URI
     * @var string
     */</i>
    protected static <var>$short_uri</var>      = NULL;

    <i>/**
     * Sendet einen Link-HTTP-Header
     * @param bool <var>$headonly</var> Nur bei HEAD-Requests senden?
     * @return void
     */</i>
    public static function send_header(<var>$headonly</var> = TRUE)
    {
        if (<var>$headonly</var> and ('<code class="string">HEAD</code>' != <var>$_SERVER</var>['<code class="string">REQUEST_METHOD</code>']) )
        {
            return;
        }
        if ( ! self::prepare() )
        {
            return;
        }
        header('<code class="string">Link: &lt;</code>' . self::<var>$short_uri</var> . '<code class="string">&gt;; rel="shortlink"</code>');
        return;
    }

    public static function link_elem(<var>$echo</var> = TRUE)
    {
        if ( ! self::prepare() )
        {
            return;
        }
        <var>$link</var> = '<code class="string">&lt;link rel="alternate shortlink" title="Shortlink"</code>'
                . '<code class="string"> href="</code>' . self::<var>$short_uri</var> . '<code class="string">" /&gt;</code>';

        if ( ! <var>$echo</var>)
        {
            return <var>$link</var>;
        }

        echo <var>$link</var>;
        return;

    }

    <i>/**
     * Erzeugt einen Link zum Twittern der aktuellen Seite.
     * @param string|array <var>$args</var>
     * @return string
     */</i>
    static function tweet_link(<var>$args</var> = NULL)
    {
        <var>$message_template</var> = '<code class="string">Lese gerade: %TITLE %URL von @toscho</code>';
        <var>$link_text</var>        = '<code class="string">Artikel twittern</code>';
        <var>$title_length</var>     = 80;
        <var>$class</var>            = '<code class="string">twitterlink</code>';
        <i>// Zum Ändern echo=0 übergeben.</i>
        <var>$echo</var>             = TRUE;

        if ( ! is_null(<var>$args</var>) )
        {
            if ( is_array(<var>$args</var>) )
            {
                extract(<var>$args</var>);
            }
            elseif ( is_string(<var>$args</var>) )
            {
                parse_str(<var>$args</var>);
            }
            else
            {
                trigger_error(
                    '<code class="string"><var>$args</var> muss ein Array oder ein String sein.</code>',
                    E_USER_ERROR
                );
            }
        }
        global <var>$post</var>;

        <var>$title</var>       = trim(<var>$post</var>-&gt;post_title);

        if ( isset ( <var>$title</var>[<var>$title_length</var>+2] ) )
        {<i>// Verkürzen bei Bedarf</i>
            <var>$title</var> = self::end_on_word(substr(<var>$title</var>, 0, <var>$title_length</var>)) . '<code class="string"> …</code>';
        }

        <var>$message</var> = str_replace(
            array('<code class="string">%TITLE</code>', '<code class="string">%URL</code>'),
            array(<var>$title</var>, self::<var>$short_uri</var> ),
            <var>$message_template</var>
        );

        <var>$link</var> = '<code class="string">&lt;a class="</code>' . <var>$class</var>
            . '<code class="string">" href="http://twitter.com/home?status=</code>' . urlencode(<var>$message</var>)
            . '<code class="string">" title="</code>' . <var>$message</var> . '<code class="string">"&gt;</code>'
            . <var>$link_text</var> . '<code class="string">&lt;/a&gt;</code>';

        if (<var>$echo</var>)
        {
            echo <var>$link</var>;
            return;
        }

        return <var>$link</var>;
    }

    <i>/**
     * Prüft, ob eine Short-URI erstellt werden soll
     * @return bool
     */</i>
    public static function prepare()
    {
        if ( is_front_page() )
        {
            return FALSE;
        }
        if ( is_page() or is_single() or is_attachment() )
        {
            global <var>$post</var>;

            if ( is_null( self::<var>$short_uri</var> ) )
            {
                self::<var>$short_uri</var> =
                    rtrim(get_option('home'), '<code class="string">/</code>') . '<code class="string">/p</code>' . <var>$post</var>-&gt;ID;
            }
            return TRUE;
        }
        <i>// Archive</i>
        return FALSE;
    }

    <i>/**
     * Entfernt unvollständige Worte am Ende eines Strings.
     * @see http://toscho.de/2009/php-funktion-end_on_word/
     * @param <var>$str</var> Zeichenkette
     * @return string
     */</i>
    static function end_on_word(<var>$str</var>)
    {
        <var>$str</var> = trim(<var>$str</var>);

        <i>// Nur ein Wort, wird also nicht gekürzt.</i>
        if ( FALSE === strpos(<var>$str</var>, '<code class="string"> </code>') )
        {
            return <var>$str</var>;
        }

        <i>// Jedes Wort ein Eintrag im Array …</i>
        <var>$arr</var>   = explode('<code class="string"> </code>', <var>$str</var>);
        <i>// … letztes Stück wegwerfen …</i>
        array_pop(<var>$arr</var>);
        <i>// … den String wieder herstellen und Kommas trimmen.</i>
        return rtrim( implode('<code class="string"> </code>', <var>$arr</var>), '<code class="string">,;</code>');
    }
}</pre>
<p>Wer bis hierhin durchgehalten hat, darf sich das auch als …</p>
<p class="downloadlink"><a class='piwik_download' href="http://f.toscho.de/php-skripte/short-uri.0.1.zip">WordPress-Plugin Short-URI herunterladen</a>.</p>
<p>Den Tweetlink baut ihr <em>innerhalb des Loops</em> mit diesem Code ein:</p>
<pre class="notranslate">do_action('tweet_link');</pre>
<p>Oder so:</p>
<pre class="notranslate">do_action('tweet_link', 'parameter=wert');</pre>
<p>Die darin enthaltene Klasse könnt ihr natürlich auch einfach in die <code>functions.php</code> einbinden, um den Code direkt zu verwenden.</p>
<p>Ich habe ihn unter die <a href="http://www.gnu.org/licenses/gpl.html">GPL 3</a> gestellt (<a href="http://toscho.de/2009/no-no-no-nofollow/#comment-1109">hallo Helmut!</a>), damit ihr damit machen könnt, was immer ihr wollt. Er ist mir länger geraten, als ich erhofft hatte; das heißt: Er hat sicher auch mehr Fehler. Findet sie!</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/wordpress-shortlinks-reloaded/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Per Cookie aus der Statistik</title>
		<link>http://toscho.de/2010/per-cookie-aus-der-statistik/</link>
		<comments>http://toscho.de/2010/per-cookie-aus-der-statistik/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 19:54:46 +0000</pubDate>
		<dc:creator>Thomas Scholz</dc:creator>
				<category><![CDATA[Browser]]></category>
		<category><![CDATA[Interna]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Webdesign]]></category>

		<guid isPermaLink="false">http://toscho.de/?p=1590</guid>
		<description><![CDATA[Wie man sich selbst auf der eigenen Website erkennt: Mit einem »geheimen« Cookie. Skript samt Download inklusive.]]></description>
			<content:encoded><![CDATA[<p>Dies sei als Ergänzung des Artikels »<a href="http://toscho.de/2010/opera-sich-selbst-aus-statistik-heraushalten/">Wie man sich selbst aus der eigenen Statistik heraushält</a>« verstanden. Dort habe ich einen angepaßten <i lang="en">User-Agent</i> vorgeschlagen.</p>
<p><a href="http://bernhardhaeussner.de/">Bernhard Häussner</a> hat ein sehr gute Alternative <a href="http://toscho.de/2010/opera-sich-selbst-aus-statistik-heraushalten/#comment-1341">genannt</a>: Einen besonderen HTTP-Header. Nun, genau dafür eignen sich Cookies gut.</p>
<p>Das könnte so aussehen: Man legt sich irgendwo eine Datei hin, die das spezielle Cookie erzeugt und fragt dieses später ab, wenn man den Tracking-Code einbaut.</p>
<pre class="notranslate">&lt;?php
<i>/**
 * Setzt ein Cookie, das den Benutzer identifiziert.
 */</i>
header('<code class="string">Content-Type: text/html;charset=utf-8</code>');
<i>// Wenn man auch Subdomains erfassen will, schreibe man ».example.com«</i>
<var>$domain</var>     = <var>$_SERVER</var>['<code class="string">HTTP_HOST</code>'];

<i>// Passwort-Hash (md5). Bitte ändern!</i>
<var>$password</var>   = '<code class="string">5319bef941e8a2099c98011b799c56c1</code>'; <i>// krafutzel</i>

<i>// Höchstmöglicher Wert des UNIX timestamps = 19. 01. 2038, 03:14:07</i>
<var>$expires</var> = 2147483647;

<i>// Wie soll das Cookie heißen?</i>
<var>$cookiename</var> = '<code class="string">excludeme</code>';

<var>$buttontext</var> = array('<code class="string">Cookie setzen</code>', '<code class="string">Cookie löschen</code>');

<var>$now_button</var> = <var>$buttontext</var>[(isset (<var>$_COOKIE</var>[<var>$cookiename</var>]) ? 1 : 0)];

<var>$info</var> = FALSE;

if ( '<code class="string">POST</code>' == <var>$_SERVER</var>['<code class="string">REQUEST_METHOD</code>'] )
{
    if ( !isset ( <var>$_POST</var>['<code class="string">pass</code>'] ) or ( md5(<var>$_POST</var>['<code class="string">pass</code>']) != <var>$password</var> ) )
    {
        <var>$info</var> = '<code class="string">&lt;p&gt;Gib das richtige Passwort an.</code>';
    }

    if ( !isset ( <var>$_POST</var>['<code class="string">action</code>'] ) )
    {
        <var>$info</var> = '<code class="string">&lt;p&gt;Drück den Button!</code>';
    }

    <i>// Cookie löschen</i>
    if ( <var>$buttontext</var>[1] == <var>$_POST</var>['<code class="string">action</code>'] )
    {
        <var>$expires</var> = time() - 3600;
        <var>$info</var> = '<code class="string">&lt;p&gt;Cookie wurde gelöscht.</code>';
    }
    <i>// Cookie anlegen</i>
    elseif ( <var>$buttontext</var>[0] == <var>$_POST</var>['<code class="string">action</code>'] )
    {
        <var>$info</var> = '<code class="string">&lt;p&gt;Cookie wurde angelegt.</code>';
        <var>$now_button</var> = <var>$buttontext</var>[1];
    }

    setcookie(<var>$cookiename</var>, 1, <var>$expires</var>, '<code class="string">/</code>', <var>$domain</var>, FALSE, TRUE);
}
?&gt;
&lt;!Doctype html&gt;
&lt;title&gt;Keksdose&lt;/title&gt;
&lt;?php
<i>// Feedback</i>
<var>$info</var> and print <var>$info</var>;
?&gt;
&lt;form method="<code class="string">POST</code>" action="&lt;?php print <var>$_SERVER</var>['<code class="string">REQUEST_URI</code>']; ?&gt;"&gt;
  &lt;label for="<code class="string">pass</code>"&gt;Passwort:&lt;/label&gt;
    &lt;input required name="<var>pass</var>" id="<code class="string">pass</code>" type="<code class="string">password</code>" size="<code class="string">20</code>" autofocus&gt;
  &lt;input type="<code class="string">submit</code>" name="<code class="string">action</code>" value="&lt;?php echo <var>$now_button</var>; ?&gt;"&gt;
&lt;/form&gt;
&lt;?php
if ( isset ( <var>$_COOKIE</var>[<var>$cookiename</var>] ) )
{
    print '<code class="string">&lt;h2&gt;All deine Cookies für diese Seite:&lt;/h2&gt;&lt;pre&gt;</code>'
        . var_export(<var>$_COOKIE</var>, TRUE) . '<code class="string">&lt;/pre&gt;</code>';
}</pre>
<p class="downloadlink"><a class='piwik_download' href="http://f.toscho.de/php-skripte/homecookie.zip">Download homecookie.zip</a></p>
<p>Jetzt bindet man den Tracking-Code nur dann ein, wenn das Cookie fehlt – deshalb empfehle ich, den Cookienamen anzupassen.</p>
]]></content:encoded>
			<wfw:commentRss>http://toscho.de/2010/per-cookie-aus-der-statistik/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
