ek

Beiträge zum Thema JS, HTML, CSS & anderem Kram

Require.js

Angenommen man lädt mit seine JavaScript-Dateien mit Require.js, wobei man über das data-main-Attribut die Require.js-Konfiguration anspricht und innerhalb dieser mithilfe der deps-Eigenschaft die weiteren benötigten Dateien anmeldet. Hat man nun keine klassiche “Single-page App”, sondern mehrere Unterseiten, auf welchen man unterschiedliche Funktionalitäten anbieten möchte, hat man drei Möglichkeiten:

  1. Man verpackt alles in eine JavaScript-Datei und lädt diese auf allen Unterseiten
    Das ist ziemlich unelegant und läuft der Idee von Require.js, JavaScript zu modularisieren, zuwider.
  2. Man legt für jeden Unterseite eine Config-Datei an, die das gewünschte, zur Unterseite gehörige Script lädt
    Auch dies ist unelegant, da es Redundanz und unnötigen Overhead erzeugt.
  3. Man definiert am Script-Tag, welches die Require.js-Library einbindet, seitenspezifische Umgebungsvariablen
    Dazu im folgenden mehr …

Der Trick bei letzterer Herangehensweise ist, mithilfe des HTML5-data-Attributs weitere Informationen zu übergeben und dem Script-Tag eine ID zu verpassen, so dass es einfach angesprochen werden kann. Dadurch hat man die Möglichkeit, mit einer Konfigurationsdatei flexibel auf die jeweilige Unterseite zu reagieren.

Folgendermaßen sieht das Einbinden von Require.js aus:

HTML

<script src="path/to/require.js" id="requirejs" data-main="path/to/config" data-env="about" data-devmode="1"></script>

require.js und die config.js werden geladen. Soweit, so normal. Außerdem wird mithilfe von data-env definiert, dass es sich bei der aktuellen Seite um die “About”-Seite handelt, und mithilfe von data-devmode weiterhin festgelegt, dass der Entwicklungsmodus aktiv ist. Bei letzterem muss man auf “0” und “1” zurückgreifen, da die Attributwerte immer als String ausgelesen werden. “true” und “false” wären als nicht-leere Strings also beide in der Abfrage true.

“0” und “1” jedoch kann man über den Umweg Integer in Boolean umwandeln. Dies geht mithilfe von Bitwise-Operatoren folgendermaßen:

JavaScript

typeof ('1337' | 0) // => "number"

Die zu ladene config.js sieht dann folgendermaßen aus:

JavaScript

var requirejsElem = document.getElementById('requirejs');

require.config({

    deps : (function () {
        return [requirejsElem.getAttribute('data-env') + '.main']
    })(),

    urlArgs : (function () {
        return !!(requirejsElem.getAttribute('data-devmode')|0)
            ? 'bust=' + Date.now()
            : '';
    })(),

    paths : {
        jquery : 'libs/jquery-1.8.2.min'
    }

});

Als erstes wird das Script-Tag, welches Require.js lädt, in der Variable requirejsElem gespeichert, um bequem darauf zugreifen zu können. Dies ist zwar eine globale Variable, was es eigentlich zu vermeiden gilt, aber hier heiligt der Zweck die Mittel.

Als nächste folgt die eigentliche Require.js-Konfiguration. Die deps-Eigenschaft, welche die benötigte Applikationslogik lädt, ist nun dynamisch und spricht alle <prefix>.main.js-Dateien an. In diesen können dann die jeweils benötigten Module per require([…]) geladen werden.

Das devmode-Flag wird fürs Cache-Busting genutzt. Ist die Seite im Dev-Mode, wird an alle Script-Pfade der GET-Parameter bust angehängt und diesem der aktuelle Timecode übergeben.

Befindet sich die Seite nicht im Dev-Mode, wird der urlArgs-Eigenschaft ein leerer String übergeben und das Caching der Scripte findet statt.

Dies sind nur zwei Möglichkeiten, Require.js mithilfe des data-Attributs flexibler zu nutzen. Im täglichen Entwicklerleben ergeben sich bestimmt noch weitere praktische Anwendungsfälle. Kann man zudem sicher sein, nur für moderne Browser zu entwickeln, muss man nicht umständlich mit getAttribute hantieren, sondern kann auf die HTML5-data-Attribute-API zurückgreifen. Anstatt requirejsElem.getAttribute('data-env') reicht in dem Fall requirejsElem.dataset.env.

Das Statistik-PlugIn WordPress.com Stats ist sicherlich praktisch. Vom Umfang her eher rudimentär, doch um schnell mal im Backend zu checken, was die Besucherzahl sagt, genau richtig.

Das einzige was störend sein kann, ist das kleine Smiley, das im Blog erscheint, wenn das PlugIn aktiv ist. Doch das wird man mit vier Zeilen CSS ganz schnell los:

CSS
#wpstats {
   height: 0;
   visibility: hidden;
}

Nun ist das Bild verschwunden, wie es sich für einen "Zähl-Pixel" gehört, verrichtet jedoch weiter seinen Dienst.

Aperture - Screenshot

Aperture ist eine Photo-Editing-Software von Apple™, welche die Möglichkeit bietet, Galerien zu erstellen und im HTML-Format zu exportieren. Diese Funktion kann ich aufgrund des generierten Quelltextes nicht empfehlen, nichtsdestominder ist sie sehr praktisch für Leute, die schnell eine Galerie veröffentlichen wollen, jedoch kein HTML können.

Ein weiteres Manko ist der Umstand, dass jedes Foto eine eigene Unterseite bekommt und man sich an diesen entlang hangelt. Heutzutage allerdings - möchte ich behaupten - ist eine Lightbox Standard, wenn es um das Betrachten von Fotos im Browser geht. Deshalb möchte ich zeigen, wie man mithilfe von jQuery und einem PlugIn diese Funktionalität relativ schnell nachrüsten kann.

Als erstes benötigen wir das PlugIn jQuery lightBox. Wir entpacken das Zip-File und legen den js-Ordner, den css-Ordner und den images-Ordner aus dem jquery-lightbox-0.5-Ordner in dem aus Aperture exportierten Galerie-Ordner ab.

Nun muss das PlugIn eingebunden werden und zwar innerhalb der <head>-Tags der index.html der Galerie. Als erstes die beiden JavaScript-Dateien und das Stylesheet:

HTML
<link rel="stylesheet" type="text/css" href="css/jquery.lightbox-0.5.css" media="screen" />
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.lightbox-0.5.pack.js"></script>

Mit folgendem JavaScript-Code aktivieren wir die Lightbox:

JavaScript
$(document).ready( function() {
	$('dd.imagecell a').lightBox();
});

Nun ergibt sich allerdings das Problem, dass das Lightbox-PlugIn darauf angewiesen ist, dass die Links um die Thumbnails der Fotos auf die große Version der selben verweisen. Dies tun sie in der Aperture-Galerie allerdings nicht. Vielmehr verweist der Link auf die Unterseite, auf der die große Version des Fotos eingebunden ist. Die Links müssen also erst noch manipuliert werden, bevor die Lightbox funktioniert:

JavaScript
$(document).ready( function() {
   var link = $('dd.imagecell a');
   link.each( function(i) {
      i += 1;
      $(this).attr('href', 'pictures/picture-' + i + '.jpg');
   });
});

Mit diesem JavaScript-Code werden die Verweise auf den Thumbnails auf die großen Versionen der jeweiligen Fotos umgelenkt. Alles in allem muss man also folgendes in den <head>-Bereich der index.html schreiben:

HTML/JavaScript
<link rel="stylesheet" type="text/css" href="css/jquery.lightbox-0.5.css" media="screen" />
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.lightbox-0.5.pack.js"></script>
<script type="text/javascript">
   $(document).ready( function() {
      var link = $('dd.imagecell a');
      link.each( function(i) {
         i += 1;
         $(this).attr('href', 'pictures/picture-' + i + '.jpg');
      });
      link.lightBox();
   });
</script>

Schon habt ihr mit etwas jQuery eine moderne Lightbox in eure Aperture-Galerie eingebaut.

Noch ein Hinweis am Rande: Die Pfade zum Warte-Bild, den Pfeilen und dem Close-Button sind in der lightbox.js festgelegt. Wenn ihr den images-Ordner also nicht im Galerie-Ordner ablegt, sondern bspw. darunter, müsst ihr diese Pfad-Angaben ändern, sonst wird die Lightbox nicht richtig angezeigt.

Ansonsten gilt wie immer: Wenn es Fragen gibt, nutzt die Kommentar-Funktion!

Weiterführende Links:

Weichgezeichnete Schrift mit CSS3

Hier ein kleiner Trick, wie man mithilfe von CSS3 "Blurred Typo", also weichgezeichnete Schrift, machen kann. Das ganze funktioniert durch den Umweg über die text-shadow-Funktion in CSS3.

Um das Beispiel zu verdeutlichen habe ich eine unspektakuläre Navigation gewählt. Hier der HTML-Teil:

HTML
<ul id="nav">
	<li><a href="index.html">Home</a></li>
	<li><a href="#">About</a></li>
	<li><a href="#">Portfolio</a></li>
	<li><a href="#">Contact</a></li>
</ul>

Eine ungeordnete Liste, wie es sich für eine anständige Navigation gehört. Als nächstes der CSS-Teil:

CSS
#nav {
	width: auto;
	clear: left;
	overflow: hidden;
	border-left: 1px solid #EEE;
	list-style: none;
}

#nav li {
	width: auto;
	height: 30px;
	padding: 0 20px 20px 20px;
	float: left;
	border-right: 1px solid #EEE;
	line-height: 30px;
}

#nav li a:link,
#nav li a:visited {
	text-decoration: none;
	color: #CCC;
	text-shadow: 0 0 3px #CCC;
}

#nav li a:hover {
	text-shadow: 0 1px 1px #666;
	color: #093;
}

#nav li a:active {
	color: #999;
	text-shadow: none;
}

Indem man die X- und Y-Offset-Werte bei text-shadow gleich Null setzt, entsteht anstelle des Schatten mehr so etwas wie ein äußeres Leuchten. Da dieses Leuchten die gleiche Farbe wie die Schrift hat, wirkt diese dadurch weichgezeichnet. Beim Überfahren mit der Maus verschwindet dieser Effekt und die Schrift erscheint klar.

Da es sich um eine CSS3-Spielerei handelt, braucht man zur Darstellung einen modernen Browser, wie Safari 4, Firefox 3.5, Opera 10 oder Chrome. Im Internet Explorer geht das ganze wie erwartet nicht, was aber kein Weltuntergang ist, da die Funktion der Seite ansich dadurch nicht beeinträchtigt wird.

Seit ich diesen Blog gestartet habe, zeige ich meine drei aktuellsten Twitter-Updates mit "Twitter for WordPress" in der Sidebar an. Und seitdem werden die Umlaute zerschossen. Das ist nicht sehr schön und endlich habe ich eine Lösung gefunden, das Problem zu beheben.

Und zwar mithilfe des Plug-Ins "WP-RSS Import" von Frank Bueltge. Dieses setzt genau wie das Plug-In "Twitter for WordPress" auf die WordPress-eigene Funktion fetch_rss(), welche wiederum die Probleme verursacht.

Die Lösung besteht nun aus zwei Arrays aus Franks Plug-In:

PHP
$umlaute = array('&#8211;', '&#8212;',…);
$htmlcode = array('&ndash;', '&mdash;',…);

Die kompletten Arrays kann ich hier nicht angeben, da sie viel zu umfangreich sind. Ihr findet sie aber im SVN-System des Plug-In Directory von WordPress. Die beiden gesuchten Arrays befinden sich in der Mitte und sind eigentlich nicht zu übersehen.

Diese kopiert ihr bspw. in Zeile 70 der Datei twitter.php von "Twitter for WordPress", vor die foreach-Schleife. Als nächstes kommt die Funktion, die dafür sorgt, dass alle Umlaute, die im Array $umlaute stehen, durch die entsprechenden Entitäten aus dem Array $htmlcode ersetzt werden:

PHP
$msg = str_replace($umlaute, $htmlcode, $msg);

Das tragt ihr in Zeile 76 der twitter.php ein und schon seid ihr fertig. Von nun an werden alle mit "Twitter for WordPress" eigebundenen Tweets sauber dargestellt.

An dieser Stelle noch einmal ein Dank an Frank Bueltge für das Erstellen dieser beiden monströsen Arrays. Wer genauso wie ich nach langer, erfolgloser Suche darin endlich die Lösung für das Umlaute-Problem gefunden hat, dem möchte ich den Spenden-Button auf seiner Seite nahelegen. Einen Euro oder mehr für gute Programmier-Arbeit zu spenden ist eine schöne Geste und sorgt dafür, dass die Entwicklung im Open-Source-Bereich weiter geht.

Momentan richte ich einen WordPress-Blog auf 1und1-Webspace ein und wurde beim Hochladen von Bildern mit dem "HTTP Fehler" konfrontiert. Das Bild ist zwar auf dem Server gelandet, sogar da, wo es hin soll, doch konnte WordPress weder die Größe ermitteln, noch die obligatorischen Thumbnail- und 'Mittlere Größe'-Äquivalente anlegen.

Den "HTTP Fehler" gab es vor einiger Zeit schon einmal, beim Update auf die WordPress-Version 2.7. Damals lag es am Flash-Uploader, den man per PlugIn deaktivieren und das Problem somit lösen konnte.

In diesem Fall aber liegt es nicht am Flash-Uploader, sondern an dem Umstand, dass 1und1 die WordPress-Skripte als PHP4-Skripte parst. Richtigerweise werden diese jedoch als PHP5-Skripte geparst, was man durch folgenden Eintrag in die .htaccess-Datei erreichen kann:

.htaccess
AddType x-mapp-php5 .php
AddHandler x-mapp-php5 .php

Solltet ihr noch keine .htaccess-Datei haben, legt lokal bei euch eine leere htaccess.txt-Datei an, ladet sie ins root-Verzeichnis eurer WordPress-Installation hoch, entfernt das Suffix ".txt" und fügt einen Punkt an den Anfang des Dateinamens. Daraufhin wird die Datei wahrscheinlich verschwinden. Um sie wieder zu sehen, müsst ihr in eurem FTP-Programm das Anzeigen versteckter Dateien aktivieren.

Nun sollte der "HTTP Fehler" Vergangenheit sein.

Quelle: 1&1 Hilfe-Center

Jeder kommt früher oder später beim Bauen einer Website in die Situation, dass er die Beschriftung eines Buttons loswerden möchte, um den Button mit einer schönen Grafik zu versehen. Das Auge surft schließlich mit.

Barrierefreier Button mit Text Replacement

Oftmals sieht man in diesen Fällen, dass das value-Attribut einfach leer gelassen wird. Dies ist allerdings eine wenig elegante Lösung, da Besucher mit Screenreader raten müssen, wofür der Button gedacht ist. Alternativ könnte man auf die Standard-Text-Replacement-Methode über text-indent: -9999px; zurückgreifen. Dies funktioniert auch ganz passabel in mordernen Browsern. IE6 und IE7 schieben dabei allerdings den kompletten Button nach links ins Abseits.

Es muss also eine andere Methode her. Und die sieht so aus, dass man einfach ein div-Element um den Button packt und ihm die gleiche Größe wie dem Button gibt. Dann verschiebt man selbigen noch mittels padding-top ins Abseits und schon ist der Text weg und man kann seine Grafik einbauen. Der Quelltext dafür sieht folgendermaßen aus:

HTML
<div class="button">
   <input type="submit" value="Absenden" />
</div>

Dazu kommen noch folgende CSS-Angaben:

CSS
.button {
	height: 30px;
	width: 80px;
       overflow: hidden;
}

input {
	width: 80px;
	height: 30px;
	padding: 30px 0 0 0;
	border: 0;
	background: #369 url('button.jpg') 0 0 no-repeat;
}

Diese Technik funktioniert einwandfrei im Firefox, in Safari sowie im IE6/7/8.

Natürlich kann man den gleichen Effekt erzielen, indem man einem input-Element das Attribut type="image" gibt und die Grafik direkt im Quelltext einbaut. Allerdings hat man dann nicht die Möglichkeit, für den :hover- und :active-Zustand eine alternative Grafik per CSS zuzuweisen, was der User Experience durchaus zuträglich ist.

PS: Wie ihr input-Elemente im IE6 :hover-fähig macht, erfahrt ihr hier.

Nachtrag:

Thorsten hat mich in den Kommentaren darauf aufmerksam gemacht, dass diese Lösung im Opera-Browser nicht funktioniert, da sich dort die Button-Beschriftung nicht durch padding ins Abseits schieben lässt. Hier müssen wir also mit der üblichen Text Replacement-Methode mittels der CSS-Angabe text-indent: -9999px; ran.

Allerdings hat der Internet Explorer wie oben beschrieben seine Schwierigkeiten mit dieser Lösung und verschiebt den kompletten Button ins Abseits, was sicherlich nicht im Sinne des Erfinders ist. Wir müssen den Internet Explorer also ausschließen, was auf zwei Arten Möglich ist.

1. Über herkömmliche Conditional Tags:

HTML/CSS
<!--[if !IE]>
<style type="text/css">
  input {
    text-indent: -9999px;
  }
</style>
<![endif]-->

Dies ist die Standard-Abfrage, ob es sich beim Browser um einen Internet Explorer handelt oder nicht. Diesen -Schnipsel fügt man in den Kopf-Bereich ein und schon sieht der Button auch im Opera-Browser anständig aus.

2. Ergänzung im type-Attribut:

Ergänzt man das type-Attribut des style-Elements um die mit Apostroph abgegrenzte Angabe charset=utf-8, interpretiert der Internet Explorer die Angabe nicht mehr. Trotzdem ist das Dokument weiterhin valide.

HTML/CSS
<style type="text/css;charset=utf-8">
  input {
    text-indent: -9999px;
  }
</style>

Welche Lösung ihr wählt, sei euch überlassen. Eine Empfehlung, welche besser ist, kann ich nicht abgeben.

Ein Freund kam neulich auf mich zu fragte mich, wie er die Beiträge seines Blogs optisch trennen kann, je nachdem, welcher Autor den Beitrag geschrieben hat. Ich sagte, das sei ganz einfach und nahm — optmistisch, wie ich bin — an, die WordPress-Funktion post_class() würde u.a. auch den Namen des Autors als Klasse ausgeben. Dem ist jedoch nicht so.

Man kann den Namen des Autors aber ganz schnell mit folgendem PHP-Code hinzufügen:

PHP/HTML
<?php $curauth = get_userdata(intval($post->post_author)); ?>

<div <?php post_class($curauth->user_login) ?>>

Nun erscheint der Autorenname in der Klasse des Beitrags-div und man kann die einzelnen Posts ganz bequem per CSS optisch anpassen.

(via the english guy web design)

google analytics-Screenshot

Gerade gucke ich meine Statistiken auf Google Analytics an und muss mit Erschrecken feststellen, dass jedes mal, wenn ich beim Schreiben eines neuen Artikels diesen in der Vorschau betrachtet habe, das ganze als Page Impression festgehalten wurde. Was für ein Blödsinn, ich gucke den ganzen Tag pausenlos bei meinem Blog vorbei, und verfälsche mir damit die Statistik.

Unangenehmer wird das ganze noch, wenn man einen Blog mit mehreren Autoren betreibt. Schön, wenn die regelmäßig vorbei gucken und was schreiben, aber in der Besucherstatistik haben die nicht wirklich was verloren. Deshalb bietet es sich an, einfach alle eingeloggten User aus der Besucherzählung rauszunehmen. Und dafür fragen wir den Status ab:

PHP
<?php if (!is_user_logged_in()) : ?>
   <!-- Hier den Statistik-Code-Schnippel einfügen -->
<?php endif; ?>

Ist der Nutzer eingeloggt, wird der Zählcode nicht angezeigt. Für alle anderen, nicht eingeloggten Besucher schon. Nun muss die erste Amtshandlung beim Besuchen seiner Seite nur noch das Einloggen sein, und schon ist man raus und die Statistik zählt nur noch "echte", externe Besucher der Seite.

Wer Googlemail benutzt, kennt sicherlich die Buttons mit dem Grauverlauf und den abgerundeten Ecken, die jedoch ohne eine Grafik auskommen. So etwas kann man relativ schnell selber machen, man muss nur genug HTML-Tags "in den Topf werfen". In diesem Tutorial zeige ich euch, wie ihr das mithilfe von jQuery bewerkstelligen könnt. jQuery deshalb, weil man einfach HTML-Tags hinzufügen kann und der eigentliche Quelltext schön sauber bleibt.

navigation im googlemail-style

Und wenn wir schon beim Thema sind, fangen wir am besten mit dem Quelltext an. Dieser sieht so aus:

HTML
<ul class="navigation">
   <li><a href="index.html">Home</a></li>
   <li><a href="#">About</a></li>
   <li><a href="#">Tutorials</a></li>
   <li><a href="#">Contact</a></li>
</ul>

Eine schlanke, ungeordnete Liste, wie es sich gehört. Allerdings brauchen wir nun ein Element, um die abgerundeten Ecken darzustellen, zwei weitere Elemente um den Grauverlauf zu bilden, und nochmal zwei Elemente um die geprägte Schrift auf den Buttons hinzubekommen.

Summa sumarum müssen also 5 Tags hinzugefügt werden, um den grafischen Effekt hinzubekommen. Deshalb auch die Javascript-Lösung, da bspw. Suchmaschinen-Bots oder Menschen an Screen-Readern nichts mit dieser Fülle an HTML-Elementen anfangen können.

Hier nun die benötigten Javascript-Angaben:

Javascript
$(document).ready(function() {				
   var start = "<span class=\"layer_1\"><span class=\"layer_2\"></span><span class=\"layer_3\"></span><span class=\"layer_4\">";
   var middle = "</span><span class=\"layer_5\">";
   var end = "</span></span>";
				
   var item = new Array();
   $('.navigation li a').each( function() {
      item.push(this.innerHTML);
      for ( i = 0; i < item.length; i++ ) {
         $(this).html(start + item[i] + middle + item[i] + end);
      }					
   });
});

Als erstes werden die benötigten Elemente — in diesem Fall <span>-Tags — in Variablen gespeichert. Danach werden die jeweiligen Beschriftungen der Listen-Elemente in einem Array gespeichert. Zum Schluss wird alles zusammengefügt. Nun fehlen nur noch die entsprechenden Styles, um die Buttons fertig zu machen. Diese gestalten sich wie folgt:

CSS
body {
	padding: 100px;
	font: normal 12px Helvetica;
	font-weight: bold;
	background-color: #FFF;
}

.navigation {
	height: 20px;
	padding: 1px 0;
	clear: left;
	list-style: none;
}

.navigation li {
	position: relative;
	width: 82px;
	height: 20px;
	margin: 0 10px 0 0;
	float: left;
	display: inline;
}

a, span {
	display: block;
	text-decoration: none;
}

a:focus {
	outline: none;
}

a:link, a:visited {
	width: 82px;
	height: 20px;
	position: relative;
	background-color: #DDD;
	text-align: center;
	line-height: 20px;
	color: #333;
	z-index: 100;
	overflow: visible;
}

a:hover {
	background-color: #999;
	color: #000;
	
}

.layer_1 {
	width: 80px;
	height: 20px;
	position: absolute;
	top: -1px;
	left: 1px;
	border: 0;
	border: 1px solid #DDD;
	border-left: 0;
	border-right: 0;
	background-color: #F9F9F9;
	overflow: hidden;
	z-index: 200;
}

a:hover .layer_1 {
	border-top: 1px solid #999;
	border-bottom: 1px solid #999;
}

.layer_2 {
	width: 80px;
	height: 2px;
	position: absolute;
	top: 10px;
	left: 0;
	background-color: #EEE;
	z-index: 300;
}

a:active .layer_2 {
	top: 8px;
	left: 0;
}

.layer_3 {
	width: 80px;
	height: 8px;
	position: absolute;
	top: 12px;
	left: 0;
	background-color: #E3E3E3;
	z-index: 300;
}

a:active .layer_3 {
	top: 0;
	left: 0;
}

.layer_4 {
	width: 80px;
	height: 12px;
	position: absolute;
	top: 5px;
	left: 0;
	line-height: 12px;
	color: #FFF;
	text-align: center;
	z-index: 400;
}

.layer_5 {
	width: 80px;
	height: 12px;
	position: absolute;
	top: 4px;
	left: 0;
	line-height: 12px;
	color: #777;
	text-align: center;
	z-index: 500;
}

a:hover .layer_5 {
	color: #333;
}

Zugegeben, das ist ein ganz schöner Rattenschwanz an CSS-Angaben, aber es lohnt sich. layer_1 ist höher als das <a>-Tag und ragt oben und unten darüber hinaus. Dadurch bekommen wir die abgerundeten Ecken. layer_2 und layer_3 sind leer und erzeugen den Grauverlauf. layer_4 und layer_5 beinhalten die Beschriftung des Buttons und erzeugen den Eindruck geprägter Buchstaben, indem das untere Layer weiße Schrift und einen Offset von einem Pixel in der y-Achse hat.

Das ganze funktioniert im Internet Explorer 6-8, im Firefox, in Opera und in Safari. Andere Browser habe ich nicht getestet, allerdings sollte es mit keinem modernen Browser Probleme geben.

Für Anmerkungen nutzt bitte die Kommentarfunktion, ich freue mich immer über Anregungen und konstruktive Kritik. Solltet ihr noch keine Erfahrungen mit jQuery gemacht haben, empfehle ich euch das Einsteiger-Tutorial in den "Weiterführenden Links".

Weiterführende Links: