Formular von Anfänger - Frage zum Styling
Linus
- formulare
Hallo,
ich bin neu hier und generell in der Webseiten-Programmierung.
Ich habe ein Formular erstellt und verstehe nicht, warum das Dropdown und die Text-Felder unterschiedlich hoch sind, obwohl im css ich die selbe Höhe angegeben habe. Könnt ihr mir weiterhelfen? Außerdem würde ich mich generell zu Feedback freuen, was habe ich gut gemacht, was sollte ich anders machen?
<div class="formular-content">
<form class="formular-container">
<div class="formular-line">
<div class="formular-item">
<label for="auswahl produkt">Wähle ein Produkt</label>
<select name="auswahl-produkt" id="auswahl-produkt" class="auswahl-produkt">
<option value="Hoodie „Green Future“">
Hoodie „Green Future“
</option>
<option value="T-Shirt „Earth Tone“">
"T-Shirt „Earth Tone“
</option>
<option value="Jacket „Recycle Tech“">
"Jacket „Recycle Tech“
</option>
</select>
</div>
<div class="formular-item">
<label for="auswahl größe">Größe</label>
<select name="auswahl-produkt" id="auswahl-produkt" class="auswahl-produkt">
<option value="S">
S
</option>
<option value="M">
M
</option>
<option value="L">
L
</option>
<option value="XL">
XL
</option>
</select>
</div>
</div>
<div class="formular-line">
<div class="formular-item">
<label for="vorname">Vorname</label>
<input id="vorname" type="text" name="vorname">
</div>
<div class="formular-item">
<label for="name">Name</label>
<input id="name" type="text" name="name">
</div>
</div>
<div class="formular-line">
<div class="formular-item">
<label for="email">E-Mail-Adresse</label>
<input id="email" type="email" name="email">
</div>
</div>
<div class="formular-line">
<div class="formular-item">
<label for="straße">Straße</label>
<input id="strasse" type="text" name="strasse">
</div>
<div class="formular-item">
<label for="straße">Nummer</label>
<input id="strasse" type="text" name="strasse">
</div>
</div>
<div class="formular-line">
<div class="formular-item">
<label for="plz">PLZ</label>
<input id="plz" type="text" name="plz">
</div>
<div class="formular-item">
<label for="ort">Ort</label>
<input id="ort" type="text" name="ort">
</div>
</div>
<div class="formular-item">
<label>Kommentarfeld</h1>
<textarea cols="50" rows="10" placeholder="Fragen oder Anregungen..."></textarea>
</div>
<button type="reset">Zurücksetzen</button>
<button type="submit">Absenden</button>
</form>
</div>
.formular-item {
display: flex;
flex-direction: column;
align-items: flex-start;
flex: 1;
}
.formular-line {
display: flex;
gap: 24px;
width: 100%;
}
.formular-container {
display: flex;
gap: 8px;
flex-direction: column;
padding: 16px;
margin: 16px;
border-radius: 16px;
background-color: grey;
max-width: 600px;
}
.formular-content {
display: flex;
align-items: center;
justify-content: center;
}
input,
select,
textarea {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
background-color: bisque;
border-radius: 8px;
box-sizing: border-box;
}
@media (max-width: 750px) {
.formular-line {
flex-direction: column;
gap: 8px;
}
}
Hi,
Ich habe ein Formular erstellt und verstehe nicht, warum das Dropdown und die Text-Felder unterschiedlich hoch sind, obwohl im css ich die selbe Höhe angegeben habe.
Im hier gezeigten CSS sehe ich keine einzige Höhenangabe …
.formular-item { display: flex; flex-direction: column; align-items: flex-start; flex: 1; } .formular-line { display: flex; gap: 24px; width: 100%; } .formular-container { display: flex; gap: 8px; flex-direction: column; padding: 16px; margin: 16px; border-radius: 16px; background-color: grey; max-width: 600px; } .formular-content { display: flex; align-items: center; justify-content: center; } input, select, textarea { width: 100%; padding: 10px; border: 1px solid #ccc; background-color: bisque; border-radius: 8px; box-sizing: border-box; } @media (max-width: 750px) { .formular-line { flex-direction: column; gap: 8px; } }
cu,
Andreas a/k/a MudGuard
Hallo Linus,
im <select> Element befindet sich ein Button, der die Höhe mit beeinflusst.
Ich würde Dir vorschlagen, den input und select Elementen eine feste Höhe zu geben und auf die Flexbox im Formular-Item zu verzichten. Die brauchst Du nicht, die Formular-Lines brauchst Du auch nicht, das kannst Du über flex-wrap auf dem Form-Element (.formular-container) lösen.
Das automatische "Ausbreiten" auf die volle Form-Breite löst man durch geeignete flex-basis Werte. Das alles sollte man in em angaben, nicht in px.
Mit dem .formular-item div bin ich nicht recht glücklich, manchmal ist ein div nur ein div und die Semantik ist hier, eine Kapsel für die Flex-Items bereitzustellen. Ich lasse es mal stehen und diskutiere nicht, ob man besser ein fieldset nimmt oder die Eingabelemente zu Kindelementen der Labels machten sollte.
Denjenigen Formular-Items, die nicht zweispaltig werden sollen, habe ich die Zusatzklasse breit gegeben.
<form class="formular-container">
<div class="formular-item">
<label for="auswahl-produkt">Wähle ein Produkt</label>
<select name="auswahl-produkt" id="auswahl-produkt" class="auswahl-produkt">
<option value="Hoodie „Green Future“">Hoodie „Green Future“</option>
<option value="T-Shirt „Earth Tone“">T-Shirt „Earth Tone“</option>
<option value="Jacket „Recycle Tech“">Jacket „Recycle Tech“</option>
</select>
</div>
<div class="formular-item">
<label for="auswahl-größe">Größe</label>
<select name="auswahl-größe" id="auswahl-größe" class="auswahl-größe">
<option value="S">S</option>
<option value="M">M</option>
<option value="L">L</option>
<option value="XL">XL</option>
</select>
</div>
<div class="formular-item">
<label for="vorname">Vorname</label>
<input id="vorname" type="text" name="vorname">
</div>
<div class="formular-item">
<label for="name">Name</label>
<input id="name" type="text" name="name">
</div>
<div class="formular-item breit">
<label for="email">E-Mail-Adresse</label>
<input id="email" type="email" name="email">
</div>
<div class="formular-item breit">
<label for="straße">Straße und Hausnummer</label>
<input id="straße" type="text" name="strasse">
</div>
<div class="formular-item">
<label for="plz">PLZ</label>
<input id="plz" type="text" name="plz">
</div>
<div class="formular-item">
<label for="ort">Ort</label>
<input id="ort" type="text" name="ort">
</div>
<div class="formular-item breit">
<label for="kommentar">Kommentarfeld</label>
<textarea id="kommentar" name="kommentar" rows="10" placeholder="Fragen oder Anregungen..."></textarea>
</div>
<button type="reset">Zurücksetzen</button>
<button type="submit">Absenden</button>
</form>
flex-flow: row wrap sorgt beim Form dafür, dass die Formularelemente nebeneinander erscheinen, solange Platz ist. Danach wird umgebrochen. Wieviel nebeneinander kommt, wird auch durch flex-grow, flex-shrink und flex-basis definiert (gemeinsam in der flex-Eigenschaft angegeben). Mit einer flex-basis von 18em, also knapp die Hälfte der maximalen Form-Breite, ist im Normalfall Platz für zwei Items. Durch ein flex-grow von 1 wird sichergestellt, dass zwei Items den verfügbaren Platz auffüllen.
Einige Items sollen immer die volle Breite haben (z.B. Mail oder Kommentar), diese bekommen die Klasse breit und damit eine flex-basis von 100%. Genauso die beiden Buttons.
Straße und Hausnummer habe ich zusammengelegt, es ist nicht immer gegeben, das eine Anschrift aus Straße und Hausnummer besteht. Es ergibt weder fachlich noch technisch einen Sinn, dafür getrennte Felder vorzusehen.
Für die PLZ habe ich eine andere Flex-Basis vorgesehen, ich finde es nicht so gut, PLZ und Ort gleich breit darzustellen. Dafür habe ich keine Klasse gesetzt, sondern die :has()-Pseudoklasse genutzt, um das .formular-item auszuwählen das ein Element mit der ID plz enthält. Für den Ort habe ich dann noch flex-grow auf 999 gesetzt, damit wird die PLZ dann, wenn PLZ und Ort nebeneinander stehen, nicht sichtbar breiter. Im Fall eines schmalen Viewports behält sie aber ihr flex-grow und füllt die ganze Breite auf. Ich hatte zuerst flex-grow für die PLZ auf 0 gesetzt, es sah aber doof aus, wenn sie alleine schmal war.
Für input und select habe ich die Höhe auf 2.5em festgenagelt und kein vertikales Padding gesetzt. Der Browser gibt dann exakt so viel Padding, dass das Element die geforderte Höhe einnimmt. Für die textarea muss natürlich das vertikale Padding erhalten bleiben.
.formular-container {
display: flex;
gap: 0.25em 0.5em;
flex-flow: row wrap;
padding: 1em;
margin: 1em auto;
border-radius: 1em;
background-color: grey;
max-width: 40em;
}
.formular-item {
flex: 1 1 18em;
}
.formular-item.breit, button {
flex-basis: 100%;
}
.formular-item:has(#plz) {
flex-basis: 6em;
}
.formular-item:has(#ort) {
flex-grow: 999;
}
input,
select,
textarea {
width: 100%;
border: thin solid #ccc;
background-color: bisque;
border-radius: 8px;
box-sizing: border-box;
}
input, select {
height: 2.5em;
padding: 0 1em;
}
textarea {
padding: 1em;
}
Rolf
@@Linus
Ich habe ein Formular erstellt
Bitte zeige es – online. Oder erstelle ein Online-Beispiel, wo man sich das ansehen kann.
<option value="Hoodie „Green Future“"> Hoodie „Green Future“ </option>
Kann man machen, muss man aber nicht.
„value: Der Inhalt dieses Attributs stellt den Wert dar, der mit dem Formular übermittelt werden soll, wenn diese Option ausgewählt wurde. Ist dieses Attribut weggelassen, wird der Wert aus dem Textinhalt des Optionselements genommen.“ [MDN]
🖖 Live long and prosper
Hallo Gunnar,
MDN kann man verlinken, muss man aber nicht.
Auswahllisten mit Select im Wiki
Rolf
Lieber Linus,
Du leidest offensichtlich an Divitis. Oft ist es besser, wenn man semantischen Code schreibt. Das div-Element hat keine Bedeutung, außer der, dass es ein Blockelement ist. Wenn Du ein <div> von einem anderen unterscheiden möchtest, dann benötigst Du Klassen in Form des class-Attributes. Je mehr verschiedene Arten von Elementen Du hast, desto weniger Klassen benötigst Du, weil Du die Elementnamen anstelle von Klassennamen im CSS verwenden kannst.
Wenn man Quelltext sieht und jedes Element hat einen Klassennamen, dann ist da offensichtlich in der Semantik etwas faul. Wenn man dann sieht, dass manche Klassen exakt einmal verwendet werden, dann erhärtet sich dieser Verdacht. Warum z.B. brauchst Du die Klasse .formular-container, wenn Du stattdessen genauso gut form als Selektor verwenden könntest?
Mit dem Nachfahrenselektor braucht man .formular-line und .formular-item nicht mehr:
form > div {
/* ehemals .formular-line */
}
form > div > div {
/* ehemals .formular-item */
}
Vielleicht willst Du einmal probieren, Dein Formular als eine Liste(!) von Eingabedaten zu verstehen und deswegen auch eine Liste als Element zu verwenden:
<form ...>
<ul>
<li>
<!-- entspricht .formular-line -->
</li>
<li>
<!-- entspricht .formular-line -->
</li>
<li>
<!-- entspricht .formular-line -->
</li>
...
</ul>
</form>
Damit kann die Divitis und die Klassenseuche wirksam eingeschränkt werden:
form > ul {
list-style: none;
margin: 0;
padding: 0;
/* ehemals .formular-line */
}
form > ul > li {
/* ehemals .formular-item */
}
Lesetip: Benutzereingaben zugänglich gestalten
Warum Du Dein form-Element zusätzlich in ein div verpacken musst, wird nicht ersichtlich. Bitte zeige Dein Formular online, damit man Dir besser helfen kann.
Liebe Grüße
Felix Riesterer
Hallo Felix,
das div um das Form diente, scheint mir, zum Zentrieren. Ich bin darauf in meinem vorigen Posting nicht ausdrücklich eingegangen, habe es aber entfernt und durch einen auto-Margin in inline-Richtung ersetzt.
Ob aber li semantisch richtig ist für Formular-Items? Ist ein Formular eine Liste von Items? Ist jede Collection automatisch eine Liste? Da bin ich mir sehr im Unklaren.
Ja, sicher, mit dem div bin ich auch nicht glücklich. Das ist wohl ein erlernter Reflex. Herr Pawlow lässt ein divlein klingeln, und sofort sabbern alle semantischen Hunde los, um es zu verjagen. Ich tendiere ja zum fieldset, das tut aber unter der Haube mehr als nur zu gruppieren. Ränder, Margins und Paddings kann man per CSS eliminieren, aber es etabliert auch einen Blockformatierungskontext.
<label> mit input/textarea als Kindelement wäre eigentlich ideal. Wenn da dieses Screenreader-Problem nicht wäre. Besteht das immer noch? Oder wäre
<label for="foo">
<p>EingabeX</p>
<input id="foo" type="...">
</label>
zuverlässig Screenreader-zugänglich?
Rolf
Lieber Rolf,
Ob aber li semantisch richtig ist für Formular-Items? Ist ein Formular eine Liste von Items? Ist jede Collection automatisch eine Liste? Da bin ich mir sehr im Unklaren.
es muss nicht immer eine unsortierte Liste sein, es kann auch eine Definitionsliste sein, bei der die label-Elemente im dt-Element stehen könnten.
Ja, sicher, mit dem div bin ich auch nicht glücklich. Das ist wohl ein erlernter Reflex. Herr Pawlow lässt ein divlein klingeln, und sofort sabbern alle semantischen Hunde los, um es zu verjagen.
Mit HTML5 hat man ja nun wirklich eine Reihe an Blockelementen, die man dafür nutzen kann. Es muss nicht immer div sein, ja. Aber in aller Regel hat man doch in einem Formular Schlüssel-Wert-Paare. Das bedeutet in aller Regel links eine Bezeichnung und rechts ein wie auch immer gearteter Eingabeteil. Das ist eine Liste.
Ich tendiere ja zum fieldset, das tut aber unter der Haube mehr als nur zu gruppieren. Ränder, Margins und Paddings kann man per CSS eliminieren, aber es etabliert auch einen Blockformatierungskontext.
Semantisch gruppiert es Teile eines Formulars zu Bereichen, die mit dem legend-Element beschriftet werden. Das kann dazu da sein, ein Formular visuell zu gliedern. Muss es aber nicht. Man kann auch in jedem fieldset ein eigenes Formular haben.
<label> mit input/textarea als Kindelement wäre eigentlich ideal. Wenn da dieses Screenreader-Problem nicht wäre. Besteht das immer noch? Oder wäre
<label for="foo"> <p>EingabeX</p> <input id="foo" type="..."> </label>
Das ist mir sowas von egal, weil man es auch so lösen könnte:
<li>
<label for="nickname-id">Text</label>
<input id="nickname-id" name="nickname">
</li>
<li>
<label for="posting-id">Text</label>
<textarea id="posting-id" name="posting"></textarea>
</li>
Liebe Grüße
Felix Riesterer
@@Felix Riesterer
es kann auch eine Definitionsliste sein
Der Begriff hält sich hartnäckig, aber in HTML5 wurde dl umgewidmet zu description list.
<li> <label for="nickname-id">Text</label> <input id="nickname-id" name="nickname"> </li> <li> <label for="posting-id">Text</label> <textarea id="posting-id" name="posting"></textarea> </li>
Bei laaangen Formularen kann es insb. für Screenreader-Nutzer hilfreich sein angesagt zu bekommen, beim wievielten von wievielen Eingabefeldern sie sich gerade befinden.
„Item 1 von 47“ – ui, das kann ja ’ne Weile dauern … „Item 42 von 47“ – puh, fast geschafft!
Bei kurzen Formularen (Name – E-Mail – ab die Post) eher nicht.
🖖 Live long and prosper
Hallo Felix,
by the way ist es ja auch so, dass man in description lists zusammengehörige dt- und dd- Elemente gelegentlich als Gruppe behandeln und stylen möchte. Und statt dafür ein dg-Element oder ähnliches einzuführen, sieht die Spec vor, dafür ein - ta dah - div-Elememt zu verwenden. So falsch ist ein div gar nicht 😉
D.h. wenn man für Linus' Formular eine description list nutzte, würde man eine weitere Markup-Ebene brauchen:
dl
div
dt
label
dd
input/select/textarea
und das täte mir nicht gefallen, dann lieber ol/ul. Semantik soll das Markup ja nicht aufblähen.
@Linus - liest Du überhaupt noch mit oder haben wir Dich endverwirrt?
Rolf
@@Rolf B
Wenn da dieses Screenreader-Problem nicht wäre. Besteht das immer noch?
Es hat nie bestanden.
Oder wäre
<label for="foo"> <p>EingabeX</p> <input id="foo" type="..."> </label>zuverlässig Screenreader-zugänglich?
Ja.
Probleme macht(e?) nur Microsoft Dragon (was aber kein Screenreader ist), wenn die Verknüpfung nicht explizit mit id und for angegeben ist.
Keine Ahnung, ob Microsoft den Bug gefixt hat. Hab letztens Manuel Matuzović gefragt, der wusste es auch nicht.
🖖 Live long and prosper
@@Rolf B
<label> mit input/textarea als Kindelement wäre eigentlich ideal.
Nö, das wäre es nicht.
Es sei denn, du willst <br/> verwenden, um die Beschriftung über das das Eingabefeld zu setzen (Fig. 1).
Wir sind uns einig, dass die Beschriftung übers Eingabefeld gehört?[1]
Setzt du input { display: block }[1:1], wird das Eingabeld fokussiert, wenn man rechts daneben[2] ins Leere clickt. (Fig. 2) Das möchte man vermeiden. Da hilft auch kein input { width: fit-content }.
Die nächste Variante erfordert ein zusätzliches span um die Beschriftung. Setzt du label span { display: block }, wird das Eingabeld fokussiert, wenn man rechts[2:1] neben der Beschriftung ins Leere clict. (Fig. 3) Auch das möchte man vermeiden.
Mit Flexbox wird’s nicht besser. (Fig. 4)
Mit Grid auch nicht. (Fig. 5)
Was geht: ein Pseudoelement label span::after { display: block }. (Fig. 6) Aber will man sich das antun?
Ist input nicht in label eingebettet, sondern folgt als Geschwister, setzt man einfach nur label { display: block; width: fit-content } – fertig. (Fig. 7)
Für Radiobuttons und Checkboxen hingegen bietet es sich an, input in label zu schachteln, damit die auch gesetzt werden, wenn man auf den Zwischenraum zwischen Radiobutton/Checkbox und Beschriftung clickt.
Das könnte man auch mit padding und negativem margin erreichen, aber will man sich das antun?
label { display: block; width: fit-content } ist auch dann gut, damit die nicht gesetzt werden, wenn man rechts[2:2] neben die Beschriftung clickt.
🖖 Live long and prosper
@@Gunnar Bittersmann
… wird das Eingabeld fokussiert, wenn man rechts daneben ins Leere clickt. (Fig. 2) Das möchte man vermeiden.
… wird das Eingabeld fokussiert, wenn man rechts neben der Beschriftung ins Leere clict. (Fig. 3) Auch das möchte man vermeiden.
2, 3, 4, 5 ließen sich retten mit label { width: 0 } (bei 5 mit zusätzlichem span). ☞ Codepen-Fork
Das scheint mir aber eher ein Hack als eine gute Lösung zu sein. Unerwünschte Nebenwirkungen könnten einen einholen.
🖖 Live long and prosper
Hallo Gunnar,
Ich hätte mit deinem Pen gerne experimentiert, aber im Handy ist das unmöglich. Ständig werden meine Eingaben im CSS gelöscht.
Ich tippe margin-top, gut. Ich tippe einen Doppelpunkt, alles weg. www.dreckstool.de!
Rolf
@@Rolf B
Ich hätte mit deinem Pen gerne experimentiert, aber im Handy ist das unmöglich. Ständig werden meine Eingaben im CSS gelöscht.
Ich tippe margin-top, gut. Ich tippe einen Doppelpunkt, alles weg. www.dreckstool.de!
Damit meinst du dein Handy‽
Auf meinem iPhone hab ich kein Problem damit.
Was nicht heißt, dass ich Handys für das beste Tool hielte, um mit Codepen o.ä. zu experimentieren.
🖖 Live long and prosper
Hallo,
Auf meinem iPhone hab ich kein Problem damit.
auf meinem Samsung gehts auch.
Was nicht heißt, dass ich Handys für das beste Tool hielte, um mit Codepen o.ä. zu experimentieren.
kann man machen…
Gruß
Kalk
Hallo Gunnar Bittersmann,
keine Ahnung, was sich da auf meinem Androiden verschluckt. Auf dem Android-Tablet geht es.
Letztlich, ja, <br> hatte ich gemeint. Die Beschriftung gehört für Web-Puristen schließlich über's Eingabefeld. Was spricht gegen <br>?
Für Legacy-Designer gehört die Beschriftung dagegen links neben das Eingabefeld. So war's auf dem Mainframe, so haben wir das mit Windows Forms gemacht, so muss es auch im Web bleiben. Was ich davon halte, interessiert da keinen.
Rolf