71

I'm working on a login page for my website and I want to bold the label that comes before the input box when the text box gains focus. Right now I have the following markup:

<label for="username">Username:</label>
<input type="textbox" id="username" />

<label for="password">Password:</label>
<input type="textbox" id="password" />

I can use the adjacent selector to select the label after the text box, but I can't select the element before it. I can use this CSS selector rule, but it only selects the label after, so when the username text box gains focus, the password label becomes bold.

input:focus + label {font-weight: bold}

Is there anything I can do to make this work? I know JavaScript could be used to easily do this, but I'd like to use a purely CSS-based solution if possible, I just can't figure out a way to do it.

Dan Herbert
  • 99,428
  • 48
  • 189
  • 219

5 Answers5

40

The CSS Selectors 4 Spec provides a syntax for defining the "subject" of a selector by using a !. As of early-2016, this is not available in any browser. I'm including this because it will be the correct way to do this using pure CSS once browsers implement this syntax.

Given the markup in the question

<label for="username">Username:</label>
<input type="textbox" id="username" />

<label for="password">Password:</label>
<input type="textbox" id="password" />

This CSS would do the trick.

label:has(+ input:focus) {font-weight: bold}

Of course, this assumes browsers actually implement the subject selector and that there are no bugs related to how this syntax works with the :focus pseudo-class.

Dan Herbert
  • 99,428
  • 48
  • 189
  • 219
  • Update: About May 2014, no effect in FF 28. – Martijn Apr 29 '14 at 11:55
  • Update: Mid April 2015, no effect in FF 37 (got here again by coincedent ^_^ ) – Martijn Apr 14 '15 at 15:17
  • "*Is there a “previous sibling” CSS selector?*" question comment at http://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-css-selector#comment44596668_15503444 says that the specification allows previous sibling selection with `previous:has(+ next)`. So there seems to be a working solution probably in the current specification. – Edward Apr 07 '16 at 11:53
  • Whoops, the `:has` selector is currently, at time of writing, a W3 draft and not in the specification. For details see my comment http://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-css-selector#comment60563696_15503444. – Edward Apr 07 '16 at 12:58
  • This is actually the answer. Unluckily as of now (2022) only Safari implements this selector outside pre-release versions. https://developer.mozilla.org/en-US/docs/Web/CSS/:has – Meryovi Aug 18 '22 at 12:33
25

It would be possible to use the 'adjacent sibling selector' if the input was before the label. Just put the input before the label, and then modify the layout to put label before the input. Here's an example:

<head runat="server">
    <title></title>
    <style type="text/css">
    input:focus + label {font-weight: bold}
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div style="direction:rtl">
        <input type="text" id="username" />
        <label for="username">Username:</label>
    </div>
    <div style="direction:rtl">
        <input type="password" id="password" />
        <label for="password">Password:</label>
    </div>
    </form>
</body>

(It's kind of a hack, I would personally use javascript to do this)

input:focus + label {font-weight: bold}
<form id="form1" runat="server">
  <div style="direction:rtl">
    <input type="text" id="username" />
    <label for="username">Username:</label>
  </div>
  <div style="direction:rtl">
    <input type="password" id="password" />
    <label for="password">Password:</label>
  </div>
</form>
A.L
  • 10,259
  • 10
  • 67
  • 98
Matt Brunell
  • 10,141
  • 3
  • 34
  • 46
  • This is still good accessibility wise. They can be in any order but always always always use the 'for' and 'id' attributes. – roborourke Jan 29 '09 at 18:49
  • How portable is the input:focus? which browsers don't like it? – BuddyJoe Jan 29 '09 at 18:50
  • input:focus does not work in IE7 (I just checked.) It works in firefox. Not sure about other browsers. – Matt Brunell Jan 29 '09 at 19:00
  • Unfortunately, the above code does not work in Safari 3.2.1. I didn't take the time to understand what is wrong. Firefox, as already noted is just fine. – mouviciel Jan 29 '09 at 19:19
  • 1
    Instead of changing the direction, you could float the input to the right. – Guillermo Gutiérrez Dec 16 '14 at 14:05
  • Like "Guillermo Guitiérrez" said, you can use `#form1>div>* {float: right;}` CSS to change the order of the elements which is much better than text direction changing. The `direction: rtl;` code also produces errors like putting the colon ":" before the word "Password". Although this can be fixed with `direction: ltr;` CSS added to the label tags, using "float: right;" CSS for the label and input tags avoids all of this text direction issue. – Edward Apr 07 '16 at 11:22
  • > I would personally use javascript to do this .. Not an answer to the question. – MrYellow May 01 '18 at 22:31
8

There's no selector that will give you the previous element using CSS..

You will need to use javascript to handle what you're after.

JayTee
  • 2,776
  • 2
  • 24
  • 27
  • 1
    "*Is there a “previous sibling” CSS selector?*" question comment at http://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-css-selector#comment44596668_15503444 says that the specification allows previous sibling selection with `previous:has(+ next)`. So there seems to be a working solution probably in the current specification. – Edward Apr 07 '16 at 11:55
  • Whoops, the `:has` selector is currently, at time of writing, a W3 draft and not in the specification. For details see my comment http://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-css-selector#comment60563696_15503444. – Edward Apr 07 '16 at 12:58
5

Use this selector:

label[for=username]
{
font-weight: bold
}

this will select the label that has the value 'username' in the attribute 'for'

5

Floating the input element to the right, achieves correct element order without changing order of "Username" and ":" in the label text that you get with direction:rtl.

<style type="text/css">
    form {text-align: right;}
    input:focus + label {font-weight: bold}
    input {float:right; clear:right;}
</style>
<form>
    <div>
        <input type="text" id="username" />
        <label for="username">Username:</label>
    </div>
    <div>
        <input type="password" id="password" />
        <label for="password">Password:</label>
    </div>
</form>
Ole Helgesen
  • 3,191
  • 1
  • 18
  • 8
  • In my opinion, this is a better solution than changing text direction. For a better alignment, I would add: div {overflow: auto;} in the stylesheet. – mouviciel Jan 30 '09 at 07:28