Formulare: Datei-Element umgestalten

Ein Dateiformular, welches nicht die Standardoberfläche des Betriebssystems verwendet.Das Formularelement zum Auswählen einer Datei lässt sich nicht mittels CSS umgestalten, der Browser verwendet für dieses Element immer das Standardaussehen, so wie es vom Betriebssystem vorgegeben ist. Bei der Gestaltung von Formularen ist das natürlich ärgerlich, da das Element meistens nicht zum Aussehen der anderen Formularelemente passt.

Shaun Inman beschreibt in seinem Artikel Styling File Inputs with CSS and the DOM eine Methode diesem Element mittels Java Script und CSS trotzdem ein anderes Aussehen zu verpassen. Wie seine Methode funktioniert, und wie man sie noch verbessern/erweitern kann, erkläre ich in diesem Artikel.

Funktionsweise seiner Methode

Man erstellt ein Element, welches die Schaltfläche darstellen soll. Dieses Element kann man mit CSS gestalten, ihm beispielsweise mittels der background-Eigenschaft ein Hintergrundbild zuweisen. Innerhalb dieses Elements befindet sich dann das input-Element.

<label class="durchsuchen">
    <input type="file" name="datei" class="datei">
</label>

Dieses wird allerdings mittels opacity zu 100% transparent gemacht, so dass man es nicht sieht. Wenn man auf die sichtbare Schaltfläche klickt (also die, die man beliebig mit CSS formatieren kann), klickt man in Wirklichkeit auf die Durchsuchen-Schaltfläche des Eingabeelementes.

Verstecktes EingabefeldDie Durchsuchen-Schaltfläche ist allerdings von Betriebssystem zu Betriebssystem verschieden groß. Wenn die Schaltfläche die man selbst gestaltet hat größer ist, könnte es passieren, das man darauf klickt und nichts passiert. Deswegen muss dafür gesorgt werden, das die echte Durchsuchen-Schaltfläche immer unter der Maus ist, wenn die Maus über der “gefälschten” Schaltfläche ist. Hier kommt dann Java Script ins Spiel, sobald die Maus über der Schaltfläche ist, wird das input-Element so bewegt, das die Durchsuchen-Schaltfläche unter der Maus ist.

Diese Methode hat allerdings einen Nachteil: Es ist zwar möglich, neben der Schaltfläche noch ein Eingabefeld hinzuzufügen, welches den Dateinamen/Pfad der ausgewählten Datei anzeigt, es ist aber nicht möglich dieses Eingabeelement zu verändern, bzw. anschließend den Wert des input-Elements anzupassen/zu verändern. Das geht bei Dateielementen aus Sicherheitsgründen nicht, denn sonst könnte ein böswilliger Programmierer ja ein verstecktes Dateielement erstellen, welches ohne das der Benutzer davon etwas mitbekommt Dateien von seinem Recher hochlädt.

Vorteile:

  • Dateielemente können an das Aussehen der Webseite/der anderen Formularelemente angepasst werden.
  • Wenn der Browser des Benutzers kein Java Script unterstützt, sieht der Benutzer einfach das normale Dateielement.

Nachteile:

  • Etwas umständlich.
  • Der Benutzer kann den Pfad zur Datei nicht mehr direkt im Eingabefeld eingeben, er muss die Durchsuchen-Schaltfläche benutzen.

Ich habe auch wieder eine Demo-Seite eingerichtet: Demo.

Benutzung

Zuerst wird das Skript im head-Bereich eingebunden, dann muss/will man noch die Schaltfläche mit CSS gestalten, außerdem muss das Dateielement sich innerhalb des umgestalteten Elementes befinden. Ein Aufruf von SI.Files.stylizeAll() wendet das Skript dann an.

<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Dateielement umgestalten</title>
        <style type="text/css">         
            .SI-FILES-STYLIZED label.durchsuchen {
                /* Hier kann die Schaltflaeche gestaltet werden. */
                width:140px;
                height:30px;
                background: url('durchsuchen.png') 0 0 no-repeat;
                display:inline-block;
                overflow:hidden;
                cursor:pointer;
            }
 
            .SI-FILES-STYLIZED label.durchsuchen input.datei {
                position:relative;
                height:100%;
                width:auto;
                opacity:0;
                -moz-opacity:0;
                filter:alpha(opacity=0); 
            }
        </style>
        <script type="text/javascript" src="si.files.js"></script>
    </head>
    <body>
        <form action="..." enctype="multipart/form-data" method="post">
            <label class="durchsuchen">
                <input type="file" class="datei" name="datei">
            </label>
            <input type="submit" value="Hochladen" />
            <script type="text/javascript">
                SI.Files.stylizeAll();
            </script>
        </form>
    </body>
</html>

Das Skript weist dem html-Element die Klasse SI-FILES-STYLIZED zu. Der erste CSS-Selektor des Beispiels ist für die sichtbare Schaltfläche, hier kann diese umgestaltet werden. Der zweite Selektor sorgt dafür das das input-Element nicht sichtbar ist. Anstatt eines label-Elements kann natürlich auch irgendein anderes Element verwendet werden, die Klassennamen sind auch austauschbar.

Internet Explorer 7

Der Internet Explorer 7 macht leider ein paar Probleme, das Fenster zum Auswählen einer Datei öffnet sich, egal wo man klickt, nachdem man mit der Maus einmal über dem input-Element war. Glücklicherweise hat jemand namens jxtps eine Lösung für dieses Problem gefunden (siehe Kommentar 29 zum Artikel von Shaun Inman). Um das Problem im IE 7 zu beheben, müssen 3 Zeilen Quelltext nach Zeile 55 der si.files.js hinzugefügt werden.

51
52
53
54
55
56
57
58
59
60
61
62
var x = e.pageX - ox;
var y = e.pageY - oy;
var w = this.file.offsetWidth;
var h = this.file.offsetHeight;
 
// Fix for IE7+, otherwise the control can get dragged outside despite overflow: hidden;
if (x < 0 || y < 0 || x > this.offsetWidth || y > this.offsetHeight) { 
	x = 0; y = 0; h = 0; w = 30;
}
 
this.file.style.top	= y - (h / 2)  + 'px';
this.file.style.left	= x - (w - 30) + 'px';

Die ausgewählte Datei anzeigen

Aus Gründen der Benutzerfreundlichkeit sollte der Benutzer den Namen der ausgewählten Datei auch sehen können. Das geht ganz einfach: Man erstellt ein Element, in welches bei jeder Veränderung am input-Element der Wert von selbigem kopiert wird. Das kann ein Texteingabefeld sein, oder beispielsweise ein span-Element, ich bevorzuge letzteres, denn da der Dateiname eh nicht manuell geändert werden kann ist ein Texteingabefeld für den Benutzer ziemlich verwirrend.

<div id="d">
<!-- Hier wird das Text-Element mittels JS eingefuegt -->
    <label class="durchsuchen" id="durchsuchen">
        <input type="file" class="datei" id="datei" name="datei">
    </label>
</div>
<script type="text/javascript">
    SI.Files.stylizeAll();
 
    if (SI.Files.able) {
        var anzeige = document.createElement('span');
        anzeige.innerHTML = 'Keine Datei ausgewählt.';
        anzeige.id = 'anzeige';
 
        document.getElementById('d').insertBefore(anzeige, document.getElementById('durchsuchen'));
 
        document.getElementById('datei').onchange = function () {
            var datei = document.getElementById('datei').value;
            document.getElementById('anzeige').innerHTML = datei;
        };
    }
</script>

Das Element wird per Java Script erstellt, da Benutzer ohne JavaScript sonst trotzdem neben dem Dateielement noch “Keine Datei ausgewählt” stehen hätten.

Informationen

1 Stern2 Sterne3 Sterne4 Sterne5 Sterne (Keine Bewertung bis jetzt)
Loading ... Loading ...
Kategorie: Java Script
Ansichten: 2.640

Kommentare

Bisher wurden 2 Kommentare geschrieben.

  • Paul sagt:

    Ich hab es versucht, doch funktioniert es nicht ganz. Zum einen hab ich Probleme mit der anzeige zum anderen funktioniert der Event nicht so ganz.

    Könntest du nicht ein eigenständiges Paket zum download anbeten wo alle Daten und ein MusterQuellCode (am Stück) vorhanden ist?

Kommentar schreiben

XHTML: Folgende Elemente sind erlaubt: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Angetrieben durch Wordpress Thema erstellt von Antu