CSS highlight label BEFORE an invalid input - css

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;
}

Related

Trying to hide pseudo element on input focus through ~

I'm trying to hide parents pseudo element ::before hide on input focus and it shouldn't work on button focus. Currently it looks like this
.parent::before{
content: 'default';
}
.parent:focus-within::before{
display: none;
}
<div class="parent">
<input type="text">
<button>awd</button>
</div>
and it doesn't seem to work. I don't want to involve any js/jquery. Would be great if there any vanila css or atleast scss solution.
Thanks in advance!
You can't do that with parent focus to control pseudo element, cause button and input both trigger focus on parent, you can't approve one and disapprove another. Instead, you can wrap input to do that.
label::before{
content: 'default';
}
label:focus-within::before{
display: none;
}
<div class="parent">
<label>
<input type="text">
</label>
<button>awd</button>
</div>

CSS Parent Class over other CSS Classes

My Code Looks something like this:
input{
...
}
label{
...
}
<div class="textfield 1">
<input tpye="text" id="fullname">
<label for="fullname">Name</label>
</div>
<div class="textfield 2">
<input tpye="text" id="fullname">
<label for="fullname">Name</label>
</div>
<div class="textfield 3">
<input tpye="text" id="fullname">
<label for="fullname">Name</label>
</div>
now i want to apply the css only on one of the textfields and because the code is way to long to ad a ".textfield1" to every css element i want to ask if i can create a "parent class element" like:
.textfield1{
input{
...
}
label{
...
}
}
.textfield2{
input{
...
}
label{
...
}
}
It's like putting the styled elements in a Folder.
Is there a way to do that?
Thanks a lot in advance!
You can use:
.textfield1 input {
...
}
.textfield1 label {
...
}
Check this link for more CSS selectors combinations: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors
As Turnip mentions in comments, you cannot have spaces in classnames. So instead of having class names such as textfield 1, you could have them like textfield1 - or something else. For the time being, I am using textfield1 to demonstrate the solution.
Now, you could use the descendant selector .textfield1 input (notice the space between the class name and tag name) or the child selector .textfield2 > input (notice the arrow > between the class name and tag name) to specify that given CSS rule must apply only to the descendants or children of given class.
input{
border: 2px solid blue;
}
label{
color: blue;
}
.textfield1 input {
border: 2px solid red;
}
.textfield2 > input {
border: 2px solid yellow;
}
<div class="textfield1">
<input tpye="text" id="fullname">
<label for="fullname">Name</label>
</div>
<div class="textfield2">
<input tpye="text" id="fullname">
<label for="fullname">Name</label>
</div>
<div class="textfield3">
<input tpye="text" id="fullname">
<label for="fullname">Name</label>
</div>
If you use preprocessor like Sass or Less, you can nasted css like your example. It's not possible in the classical way.
In css:
.textfield2 input{
...
}
.textfield1 input{
...
}
.textfield1 label, //<- if the label style of textfield1 and textefield2 are same
.textfield2 label{
...
}
Be careful, in your HTML you have a space between textfield and the number <div class="textfield 3">. That's mean your div has the CSS class textfield and the CSS class 3.
If you just want one class remove the space and the code above works.
If you keep the space, just modify .textfield2 to .textfield.2 with a dot between textfield and the number (to indicate that the style it's for the class textfield with the class 2)

Is it possible to target both adjacent neighbors of a div

I want to find out if it is possible to target both neighboring elements using the middle one?
for example:
<div>
<span class="icon">icon</span>
<input id="input" class="input error" type="text" />
<label for="input"></label>
<div>
When the input has the error class I want to target the label and the span to have the color red.
I managed to make the label red with the following:
input.error ~ label {
color: red;
}
However I've had no luck with the span. Can somebody maybe tell me if this is possible? and if so please help.
You can use flexbox with the order property to re-order the elements visually, while having the input as the first element in the DOM so you can use the general sibling selector.
div {
display: flex;
}
.icon {
order: -1;
}
input.error ~ * {
color: red;
}
<div>
<input id="input" class="input error" type="text">
<span class="icon">icon</span>
<label for="input">label</label>
<div>
I used jquery .siblings() to target the span and add a class to it.
I want to find out if it is possible to target both neighboring
elements using the middle one?
You can use the axe selector % to target both neighbouring elements.
Since there is no shared class or element type between .icon and label, you'll need to declare:
input.error % .icon,
input.error % label {
color: red;
}
Alternatively, (in this case) you might combine the CSS immediate subsequent sibling selector + and the axe immediate previous sibling selector ?:
input.error ? .icon,
input.error + label {
color: red;
}

CSS/SASS previous child selection

I'm trying to make a span background change colors when I focus on an input field. The HTML is as follows:
<div class='parentDiv'>
<span class='spanClass'>Some text</span>
<input class='inputClass' type='text' />
</div>
The closest I could come to something that does this is using the + adjacent sibling selector and doing something like this:
input:focus + span {
background-color: red;
}
But it doesn't quite work because span must come after input. Is there some way for me to make the span background change colors when I focus the input field?
Normally, you would need JS to do that. Here's an example using JS that keeps styling in your CSS:
(function() {
var spanEl = document.querySelector('.parentDiv > .spanClass');
var inputEl = document.querySelector('.parentDiv > .inputClass');
// Add "highlighted" class to "spanClass" element on focus event
inputEl.addEventListener('focus', function() {
spanEl.classList.add('highlighted');
});
// Remove "highlighted" class from "spanClass" element on blur event (un-focus)
inputEl.addEventListener('blur', function() {
spanEl.classList.remove('highlighted');
});
})();
.spanClass.highlighted {
background-color: red;
}
<div class="parentDiv">
<span class="spanClass">Some text</span>
<input class="inputClass" type="text" />
</div>
In your example, though, you could simply float the one element to the left and change the order in the HTML.
.parentDiv { overflow: hidden; }
.spanClass { float: left; }
.inputClass:focus + .spanClass {
background-color: red;
}
<div class="parentDiv">
<input class="inputClass" type="text" />
<span class="spanClass">Some text</span>
</div>
Something to note for the future, though:
The :has() "relational pseudo-class" seems to be in the works for "CSS4". You can also track it here: http://caniuse.com/#feat=css-has
This means that you will (hopefully) be able to do this eventually:
.spanClass:has(+ .inputClass) {
background-color: red;
}

CSS pseudo-class :required does not work together with pseudo-element ::before

My intent is to put a * on labels of required fields.
I am testing with Chrome 47, Firefox 43 and Opera 34.
None of these can understand the CSS selector
span:required::before
According to http://caniuse.com/#feat=form-validation they all should be able to understand it, and if you use
span:hover::before
instead, it actually works.
What do I do wrong?
Here is my Code:
<!DOCTYPE HTML>
<html>
<head>
<style type="text/css">
span::before {
content: "\00A0";
}
span:required::before { /* This does NOT work! */
content: "*";
}
span:hover::before { /* But this DOES work! */
content: "_";
}
</style>
</head>
<body>
<form>
<p>
<span required>Name</span>
<input id="name" type="text" />
</p>
<p>
<span>Date of Birth</span>
<input id="birth" type="text" />
</p>
</form>
</body>
</html>
Two problems:
Form labels have a dedicated element, label. You should be using that, not span.
The required attribute only applies to the controls themselves, that is, input, select, textarea, etc. A span is just plain text (and a label is basically that on its own) and the required attribute makes no sense on such an element.1
If you're trying to style a label of a required input, you will need to give it a class name instead.
This has nothing to do with :required::before, though, given that most form elements are replaced elements, it's unlikely you'll find that pseudo-class and that pseudo-element together.
1 contenteditable notwithstanding.
The required attribute must be in the form control, and you should use labels instead of spans.
Then, you can use the selector :required + label::before. To make it work the form control must appear before the label in the DOM order, but then you can use floats or flexbox to rearrange.
p {
overflow: hidden;
}
label {
float: left;
}
label::before {
content: "\00A0";
font-family: monospace;
}
:required + label::before {
content: "*";
}
<form>
<p>
<input id="name" type="text" required />
<label for="name">Name</label>
</p>
<p>
<input id="birth" type="text" />
<label for="birth">Date of Birth</label>
</p>
</form>

Resources