Why doesn't this CSS :first-child selector work? - css

I'm working on an Asp.Net MVC 3 project and have run into a brick wall on why this doesn't work like I think it should.
My markup is:
<fieldset>
<input type="hidden" value="2">
<div class="editor-label">
<label for="Name"> Name</label>
</div>
...
</fieldset>
My css is:
.display-label, .editor-label
{
margin: 0.8em 0 0 0;
font-weight: bold;
display: inline;
}
fieldset > div:first-child
{
margin: 0;
}
All I want to do is make the first div in the fieldset have a margin of 0. I thought that the selector fieldset > div:first-child would apply the style to "the first child of a fieldset, whose type is a div", but apparently something is eluding me.
I've tried this in IE9/FF/Chrome so it's not an old browser messing with my selectors.
Thanks.

fieldset > div:first-child means "select the first child element of a fieldset if it's a div".
It does not mean "select the first div in the fieldset".
The first child in this case is <input type="hidden" value="2">.
To select that div without changing the HTML, you need to use fieldset > div:first-of-type.
Unfortunately, while :first-child is widely supported, :first-of-type only works in IE9+ and other modern browsers.
So, in this case, the best fix is to continue using fieldset > div:first-child, and simply move <input type="hidden" value="2"> so that's it's not the first child.

Related

CSS highlight label BEFORE an invalid input

Ciao, I have this element here:
<div class="uk-form-row">
<div class="md-input-wrapper md-input-filled md-input-focus">
<label>Label</label>
<input type="text" class="md-input">
<span class="md-input-bar"></span>
</div>
</div>
This is from a material design theme (Altair Admin v2) so the element once the page is loaded does this:
As you can see the label is moving around (but maybe is not a big deal).
With other elements, if they are empty (invalid) I can underline them or change their color using css:
input:invalid::-webkit-input-placeholder{
color: #e53935 !important;
}
But being this a label BEFORE the input I don't know how I can select it with CSS. How do I turn the LABEL into a different color if the input is invalid?
There is a simpler way to get this done. The :valid and :invalid pseudo-classes will automatically bubble up to a parent <fieldset>. Here is the reference.
You can take advantage of this fact to style your label like so:
<fieldset>
<label>Label</label>
<input type="text" />
</fieldset>
Then in your CSS
fieldset:invalid > label:first-of-type {
color: #e53935 !important;
}
So if your input is :invalid it will invalidate your fieldset, which you can then reference to style your label.
Look at CSS code (simplified to illustrate my point):
.md-input-wrapper {
position: relative;
}
.md-input-wrapper > label {
position: absolute;
top: 16px;
left: 4px;
right: 0;
}
Label is positioned absolutely relative to wrapper, so you can put label element after input element in HTML:
<div class="md-input-wrapper">
<input type="text" class="md-input">
<span class="md-input-bar"></span>
<label>Label</label>
</div>
After that, you can use General sibling combinator to select label of invalid input:
input:invalid ~ label {
color: red;
}

Style the first legend element within a nested fieldsets

I'm trying to style the first legend element within nested fieldsets, but none of the CSS selectors I used achieve what I'm after.
http://codepen.io/anon/pen/epodxd
I basically want to style the first legend element without using any additional CSS class if possible.
<fieldset class="nested-parent">
<legend>Parent</legend>
<input type="text" size="10" />
<fieldset>
<legend>Child</legend>
<input type="text" size="20" />
</fieldset>
</fieldset>
.nested-parent legend:first-child {
color: red;
}
Based on the HTML you provided, you could use the child selector, > in order to select the first legend element that is a direct child of the .nested-parent element:
.nested-parent > legend:first-child {
color: #f00;
}
I would suggest using the :first-of-type pseudo class instead though. It will be more accurate when dealing with the element's types.
Example Here
.nested-parent > legend:first-of-type {
color: #f00;
}

CSS unable to select last-child of p element

I have a container with several p elements and several input elements. I need to select the last p element inside this container, and for some reason I'm not able to. I've tried several methods but non seem to work. It must be last-child and not nth-child since there might be more elements in the future. Whats the difference between last-of-type and p:last-child?
JSfiddle here.
HTML:
<div id="inputContainer">
<p class="contact_title">EMAIL</p>
<p>john#snow</p>
<p class="contact_title">PHONE</p>
<p>123-hodor-hodor</p>
<p class="contact_title">ADDRESS</p>
<p>castle black</p>
<input id="name" placeholder="Name">
<input id="email" type="email" placeholder="Email">
<input id="phone" type="number" placeholder="Phone">
<textarea id="note" placeholder="bla bla"></textarea>
</div>
CSS:
/* not working 1 */
#inputContainer :last-of-type p {
color: red !important;
}
/* not working 2
#inputContainer > p:last-child {
color: red !important;
}
not working 3
#inputContainer p:last-child {
color: red !important;
} */
use css selectors in this way..it will work. use p before last of type..or else it won't work.
#inputContainer p:last-of-type {color:red;}
:last-of-type is the last element of this specific type...
So p:last-of-type would be the last p element amond all the siblings.
:last-child only triggers if it really is the last child
<div>
<p></p>
<p></p>
</div>
Here the second <p> would trigger p:last-child, because it is the last child of the <div> element
<div>
<p></p>
<p></p>
<img />
</div>
Here p:last-child would not trigger, because neither of the 2 <p> are the last child of it's parent, in fact the last child is an <img>
p:last-of-type would be triggered by the 2nd <p> though, because that is the last <p> among all 3 siblings

Using :after pseudoelement with :required pseudoclass

Pardon me if this question is already answered, but I couldn't find it.
I am trying to put an asterisk after all <input required> elements.
I found that I can style these with the :required selector.
I would like to use the :after pseudoelement to add an asterisk.
My CSS:
*:required:after {
content:"*";
font-size:48px;
color:red;
position:relative;
top:9px;
}
In Opera 30 and Chrome 40, I see this (note that nearly all of these have the required attribute, see code below.):
In Firefox 39, IE 11, and Edge no pseudoelements are displayed.
Why is it that the pseudoelement only displays on the <input type="date"/> and not on any of the other inputs or selects? And, more importantly, how can I make it display on all required elements?
I'm using bootstrap3 and jquery, if that matters.
HTML:
<label>Title
<select name="title" id="title" class="form-control" required> <!-- Trigger Gender here I think... -->
<option value="Mr.">Mr.</option>
<option value="Mrs.">Mrs.</option>
<option value="Miss">Miss</option>
<option value="Ms.">Ms.</option>
<option value="Dr.">Dr.</option>
<option value="Rev.">Rev.</option>
</select>
</label>
<label>First Name (as on Passport) <input type="text" name="firstName" id="firstName" placeholder="Charles" class="form-control" required/></label>
<label>Last Name (as on Passport) <input type="text" name="lastName" id="lastName" placeholder="Studd" class="form-control" required/></label>
<label>Maiden Name (if applicable) <input type="text" name="maidenName" id="maidenName" class="form-control"/></label>
<label>Other Names <textarea name="aliases" id="aliases" placeholder="C. T. Studd" class="form-control"></textarea></label>
<label>Date of Birth <input type="date" name="birthday" id="birthday" class="form-control" placeholder="12/02/1860" required/></label>
<label>Gender Autofilled
<select name="gender" id="gender" class="form-control" required>
<option value="male">Male</option>
<option value="female">Female</option>
</select>
</label>
Note that the spec says: Note. This specification does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML). This will be defined in more detail in a future specification. So this is not invalid behavior.
Pseudo-elements don't work on inputs, because inputs are empty elements. You'll have to put an element after each input, then use the :required pseudo-class and the + combinator to style that.
:after or :before doesn't work on input or img elements. It can be used on container elements e.g. <div></div>
Reference
In your case I suggest you make use of label instead of input elements. Add a class for label elements which has a required input inside. Of course this would need a bit more of work since you have to set the positions correctly.
e.g.
<label class="required-container">
First Name (as on Passport)
<input type="text" name="firstName" id="firstName" placeholder="Charles" class="form-control" required/>
</label>
Your css:
label.required-container:after {
content:"*";
font-size:48px;
color:red;
position:relative;
top:9px;
}
Currently, the spec does not define behavior of pseudoelements with replaced elements, so this is not required to be consistent across browsers or even within browsers apparently.
The reason is that insertion using content makes a replaced element, and replaced replaced elements are not yet defined. From MDN, replaced elements are: external objects whose representation is independent of the CSS. Typical replaced elements are <img>, <object>, <video> or form elements like <textarea> and <input>. Some elements, like <audio> or <canvas> are replaced elements only in specific cases. Objects inserted using the CSS content properties are anonymous replaced elements.
Until an indeterminate future draft, the best bet is either to use the *:required+:after selector with an empty span (or whatever) or use :required pseudoclass with something that can be used with a replaced element, like a background-image.
We can hope that the current behavior of -webkit- in replacing content:'' after type='date' points toward allowing pseudoelements on all elements. We'll see.
One way to influence what is displayed "in the" input based on one of the input's attributes is to simply place a span or any other suitable element after the input. Then, it is just simple linking via adjacent selector.
Fiddle: http://jsfiddle.net/hvzjf002/.
HTML:
<label>
<input type = "text" required/><span></span>
</label>
CSS:
label {
display: inline-block;
position: relative;
}
label > input {
height: 25px;
font: normal 14px/25px Sans-Serif;
padding: 0 25px 0 10px;
border-radius: 5px;
border: 1px solid #aaa;
outline: 0;
}
label > input:required + span:before {
content:"\f069";
font: normal 14px/1 "Font Awesome";
color: red;
position: absolute;
bottom: 50%;
right: 5px;
transform: translateY(50%);
}

Applying last-child to element not working

Given I have the following tags:
<div id="div-one">
<div class="div-two">some </div>
<input type="hidden" value=""/>
<div class="div-two">some </div>
<input type="hidden" value=""/>
<div class="div-two">some </div>
<input type="hidden" value=""/>
</div>
When I try to apply a style to the last "div-two" element using this css syntax:
#div-one div.div-two:last-child { border-bottom:solid 1px #999; }
It doesn't work unless I remove the hidden fields. Any suggestions as to why?
Here's a link to the jsfiddle: http://jsfiddle.net/67qYJ/1/
Using Google Chrome v12.0.742.100
It is NOT an option to place the hidden tags elsewhere
Your selector doesn't work for your current markup because the last child is an input, not a div.div-two.
Is div#div-one only going to contain those two kinds of elements? If so, you can use :last-of-type instead, which picks the last div (though regardless of its class):
#div-one div:last-of-type { border-bottom:solid 1px #999; }
However if your inner div elements have other classes besides .div-two, it will be pretty difficult to choose the last .div-two element. Your given code makes it easy because div and input are distinct element types and only the .div-two class is present.
If you can't use last-of-type like #BoltClock suggested you could just add a second class to the last .div-two in the group.
http://jsfiddle.net/watss/
<div class="div-two last">some </div>
and
#div-one > .div-two.last { border-bottom:1px solid; background:yellow; }
or better yet
#div-one > .last { border-bottom:1px solid; background:yellow; }

Resources