[html] :not(:empty) CSS selector is not working?

I'm having a heck of a time with this particular CSS selector which does not want to work when I add :not(:empty) to it. It seems to work fine with any combination of the other selectors:

input:not(:empty):not(:focus):invalid { border-color: #A22; box-shadow: none }

If I remove the :not(:empty) part, it works just fine. Even if I change the selector to input:not(:empty) it still won't select input fields which have text typed into them. Is this broken or am I just not allowed to use :empty within a :not() selector?

The only other thing I can think of is that browsers are still saying that the element is empty because it has no children, just a "value" per say. Does the :empty selector not have separate functionality for an input element versus a regular element? This doesn't seem probable though because using :empty on a field and typing something into it will cause the alternate effects to go away (because it is no longer empty).

Tested in Firefox 8 and Chrome.

This question is related to html css css-selectors

The answer is


Being a void element, an <input> element is considered empty by the HTML definition of "empty", since the content model of all void elements is always empty. So they will always match the :empty pseudo-class, whether or not they have a value. This is also why their value is represented by an attribute in the start tag, rather than text content within start and end tags.

Also, from the Selectors spec:

The :empty pseudo-class represents an element that has no children at all. In terms of the document tree, only element nodes and content nodes (such as DOM text nodes, CDATA nodes, and entity references) whose data has a non-zero length must be considered as affecting emptiness;

Consequently, input:not(:empty) will never match anything in a proper HTML document. (It would still work in a hypothetical XML document that defines an <input> element that can accept text or child elements.)

I don't think you can style empty <input> fields dynamically using just CSS (i.e. rules that apply whenever a field is empty, and don't once text is entered). You can select initially empty fields if they have an empty value attribute (input[value=""]) or lack the attribute altogether (input:not([value])), but that's about it.


Since placeholder disappear on input, you can use:

input:placeholder-shown{
    //rules for not empty input
}

pure css solution

input::-webkit-input-placeholder {
    opacity: 1;
    -webkit-transition: opacity 0s;
    transition: opacity 0s;
    text-align: right;
}
/* Chrome <=56, Safari < 10 */
input:-moz-placeholder {
    opacity: 1;
    -moz-transition: opacity 0s;
    transition: opacity 0s;
    text-align: right;
}
/* FF 4-18 */
input::-moz-placeholder {
    opacity: 1;
    -moz-transition: opacity 0s;
    transition: opacity 0s;
    text-align: right;
}
/* FF 19-51 */
input:-ms-input-placeholder {
    opacity: 1;
    -ms-transition: opacity 0s;
    transition: opacity 0s;
    text-align: right;
}
/* IE 10+ */
input::placeholder {
    opacity: 1;
    transition: opacity 0s;
    text-align: right;
}
/* Modern Browsers */

*:focus::-webkit-input-placeholder {
   opacity: 0;
   text-align: left;
}
/* Chrome <=56, Safari < 10 */
*:focus:-moz-placeholder {
    opacity: 0;
    text-align: left;
}
/* FF 4-18 */
*:focus::-moz-placeholder {
    opacity: 0;
    text-align: left;
}
/* FF 19-50 */
*:focus:-ms-input-placeholder {
    opacity: 0;
    text-align: left;
}
/* IE 10+ */
*:focus::placeholder {
    opacity: 0;
    text-align: left;
}
/* Modern Browsers */

input:focus {
    text-align: left;
}

input:not([value=""])

This works because we are selecting the input only when there isn't an empty string.


This should work in modern browsers:

input[value]:not([value=""])

It selects all inputs with value attribute and then select inputs with non empty value among them.


You could try using :placeholder-shown...

_x000D_
_x000D_
input {
  padding: 10px 15px;
  font-size: 16px;
  border-radius: 5px;
  border: 2px solid lightblue;
  outline: 0;
  font-weight:bold;
  transition: border-color 200ms;
  font-family: sans-serif;
}

.validation {
  opacity: 0;
  font-size: 12px;
  font-family: sans-serif;
  color: crimson;
  transition: opacity;
}

input:required:valid {
  border-color: forestgreen;
}

input:required:invalid:not(:placeholder-shown) {
  border-color: crimson;
}

input:required:invalid:not(:placeholder-shown) + .validation {
  opacity: 1;
}

  
_x000D_
<input type="email" placeholder="e-mail" required>
<div class="validation">Not valid</span>
_x000D_
_x000D_
_x000D_

no great support though... caniuse


It is possible with inline javascript onkeyup="this.setAttribute('value', this.value);" & input:not([value=""]):not(:focus):invalid

Demo: http://jsfiddle.net/mhsyfvv9/

_x000D_
_x000D_
input:not([value=""]):not(:focus):invalid{_x000D_
  background-color: tomato;_x000D_
}
_x000D_
<input _x000D_
  type="email" _x000D_
  value="" _x000D_
  placeholder="valid mail" _x000D_
  onchange="this.setAttribute('value', this.value);" />
_x000D_
_x000D_
_x000D_


You may approach this differently; omit the use of the :empty pseudo-class and utilize input events to detect a significant value in the <input> field and style it accordingly:

_x000D_
_x000D_
var inputs = document.getElementsByTagName('input');_x000D_
_x000D_
for (var i = 0; i < inputs.length; i++) {_x000D_
  var input = inputs[i];_x000D_
  input.addEventListener('input', function() {_x000D_
    var bg = this.value ? 'green' : 'red';_x000D_
    this.style.backgroundColor = bg;_x000D_
  });_x000D_
}
_x000D_
body {_x000D_
  padding: 40px;_x000D_
}_x000D_
#inputList li {_x000D_
  list-style-type: none;_x000D_
  padding-bottom: 1.5em;_x000D_
}_x000D_
#inputList li input,_x000D_
#inputList li label {_x000D_
  float: left;_x000D_
  width: 10em;_x000D_
}_x000D_
#inputList li input {_x000D_
  color: white;_x000D_
  background-color: red;_x000D_
}_x000D_
#inputList li label {_x000D_
  text-align: right;_x000D_
  padding-right: 1em;_x000D_
}
_x000D_
<ul id="inputList">_x000D_
  <li>_x000D_
    <label for="username">Enter User Name:</label>_x000D_
    <input type="text" id="username" />_x000D_
  </li>_x000D_
  <li>_x000D_
    <label for="password">Enter Password:</label>_x000D_
    <input type="password" id="password" />_x000D_
  </li>_x000D_
</ul>
_x000D_
_x000D_
_x000D_

Related


Disclaimer: note that input events are currently experimental, and probably not widely supported.


Another pure CSS solution

_x000D_
_x000D_
.form{_x000D_
  position:relative;_x000D_
  display:inline-block;_x000D_
}_x000D_
.form input{_x000D_
  margin-top:10px;_x000D_
}_x000D_
.form label{_x000D_
    position:absolute;_x000D_
    left:0;_x000D_
    top:0;_x000D_
    opacity:0;_x000D_
    transition:all 1s ease;_x000D_
}_x000D_
input:not(:placeholder-shown) + label{_x000D_
    top:-10px;_x000D_
    opacity:1;_x000D_
}
_x000D_
<div class="form">_x000D_
    <input type="text" id="inputFName" placeholder="Firstname">_x000D_
    <label class="label" for="inputFName">Firstname</label>_x000D_
</div>_x000D_
<div class="form">_x000D_
    <input type="text" id="inputLName" placeholder="Lastname">_x000D_
    <label class="label" for="inputLName">Lastname</label>_x000D_
</div>
_x000D_
_x000D_
_x000D_


input:not(:invalid){
 border: 1px red solid;
}

// or 

input:not(:focus):not(:invalid){
 border: 1px red solid;
}

_x000D_
_x000D_
.floating-label-input {_x000D_
  position: relative;_x000D_
  height:60px;_x000D_
}_x000D_
.floating-label-input input {_x000D_
  width: 100%;_x000D_
  height: 100%;_x000D_
  position: relative;_x000D_
  background: transparent;_x000D_
  border: 0 none;_x000D_
  outline: none;_x000D_
  vertical-align: middle;_x000D_
  font-size: 20px;_x000D_
  font-weight: bold;_x000D_
  padding-top: 10px;_x000D_
}_x000D_
.floating-label-input label {_x000D_
  position: absolute;_x000D_
  top: calc(50% - 5px);_x000D_
  font-size: 22px;_x000D_
  left: 0;_x000D_
  color: #000;_x000D_
  transition: all 0.3s;_x000D_
}_x000D_
.floating-label-input input:focus ~ label, .floating-label-input input:focus ~ label, .floating-label-input input:valid ~ label {_x000D_
  top: 0;_x000D_
  font-size: 15px;_x000D_
  color: #33bb55;_x000D_
}_x000D_
.floating-label-input .line {_x000D_
  position: absolute;_x000D_
  height: 1px;_x000D_
  width: 100%;_x000D_
  bottom: 0;_x000D_
  background: #000;_x000D_
  left: 0;_x000D_
}_x000D_
.floating-label-input .line:after {_x000D_
  content: "";_x000D_
  display: block;_x000D_
  width: 0;_x000D_
  background: #33bb55;_x000D_
  height: 1px;_x000D_
  transition: all 0.5s;_x000D_
}_x000D_
.floating-label-input input:focus ~ .line:after, .floating-label-input input:focus ~ .line:after, .floating-label-input input:valid ~ .line:after {_x000D_
  width: 100%;_x000D_
}
_x000D_
<div class="floating-label-input">_x000D_
      <input type="text" id="id" required/>_x000D_
      <label for="id" >User ID</label>_x000D_
      <span class="line"></span>_x000D_
</div>
_x000D_
_x000D_
_x000D_


I was trying to copy Gmail Login. When you click on "Email or phone" and type something on it the label translatesY(-38px) and scales(0.75).
What I did:-

<input type='email' class='email' placeholder=' ' />

Then In my CSS

input:not(:placeholder-shown){
//put my styles here and I got the expected results
}

If you try it and find any problem. Please share it.


Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to css

need to add a class to an element Using Lato fonts in my css (@font-face) Please help me convert this script to a simple image slider Why there is this "clear" class before footer? How to set width of mat-table column in angular? Center content vertically on Vuetify bootstrap 4 file input doesn't show the file name Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width

Examples related to css-selectors

Angular 2: How to style host element of the component? How to click a href link using Selenium How do I apply a style to all children of an element How to write a CSS hack for IE 11? :last-child not working as expected? Need to find element in selenium by css jQuery select child element by class with unknown path How do I select an element that has a certain class? What is the difference between cssSelector & Xpath and which is better with respect to performance for cross browser testing? What is the mouse down selector in CSS?