Home > Mobile >  Change another Tag Css When input Has Value
Change another Tag Css When input Has Value

Time:08-08

i have this tags in to my project, but i want to change css placeholder tag color and size ... style when my input has value. i want To Use :valid in css but I will not succeed. tip: my HTML Tags Structure Cant Change

<div >
  <input type="text" required>
</div>
<span >E-Mail</span>

my Css:

.wrapper {
  position: relative;
}

input {
  font-size: 14px;
  height: 40px;
}

.placeholder {
  position: absolute;
  font-size: 16px;
  pointer-events: none;
  left: 1px;
  top: 2px;
  transition: 0.1s ease all;
}

input:focus~.placeholder {
  top: -1px;
  font-size: 11px;
}

input[value=""]~.placeholder {
  top: -1px;
  font-size: 11px;
}

CodePudding user response:

I don't think it's possible by CSS only. You have to add a toggle class on the parent wrapper when input is focused, then there will add a class like active in the wrapper and you could write CSS like-

    wrapper.active ~ .placeholder {
    top: -1px;
      font-size: 11px;
    }

CodePudding user response:

This can't be done purely through CSS with any amount of cross-browser compatibility (yet), because the element you want to style is not a sibling, or the descendant of a sibling, of the element the changed style is a response to.

There are a couple of ways, though, if JavaScript is an option:

// simple named function to determine if the <input> element (evt.currentTarget)
// has a valid value:
const hasValue = (evt) => {
    // caching the current <input> element to which the event-handler is bound:
    let target = evt.currentTarget;
    
    // navigating to the closest ancestor element with a class of 'wrapper',
    // using the Element.classList API to toggle the class of 'childInputHasValue'
    // on the element based on whether the <input> has a valid value, in that it
    // matches the regular expression in the 'pattern' attribute:
    target.closest('.wrapper').classList.toggle('childInputHasValue', target.validity.valid)
  },
  // retrieving all <input> elements with a type attribute equal to 'text':
  inputs = document.querySelectorAll('input[type=text]');

// iterating over the <input> elements using an anonymous Arrow function with
// NodeList.prototype.forEach():
inputs.forEach(
  // binding the 'hasValue' function as the event-handler for the 'input' event
  // on each of the <input> elements:
  (el) => el.addEventListener('input', hasValue)
);
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.placeholder {
  color: crimson;
}

.wrapper.childInputHasValue   .placeholder {
  color: lime;
}
<div >
  <input type="text" required pattern="^[a-zA-Z0-9][a-zA-Z0-9\s]{5,20}$">
</div>
<span >E-Mail</span>

JS Fiddle demo.

Alternatively, if you're able to adjust your HTML to the following this can be done – quite easily – with CSS:

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.placeholder {
  color: crimson
}

input[type=text]:valid   .placeholder {
  color: lime;
}
<div >
  <input type="text" required pattern="^[a-zA-Z0-9][a-zA-Z0-9\s]{5,20}$">
  <span >E-Mail</span>
</div>

JS Fiddle demo.

However, if you're okay with (currently) poor cross-browser performance (as I write this :has() is available only in Safari and behind the "Experimental Web Platform features" flag in Chrome and Chromium), possibly using a JS shim if necessary, then you may be able to use the :has() selector:

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.placeholder {
  color: crimson;
}

.wrapper:has(input:valid)   .placeholder {
  color: lime;
}
<div >
  <input type="text" required pattern="^[a-zA-Z0-9][a-zA-Z0-9\s]{5,20}$">
</div>
<span >E-Mail</span>

JS Fiddle demo.

As for using :has() with a shim, that could be as simple as follows:

// here we check if the browser supports the ':has(input:valid)' selector, note that this is achieved
// by passing the 'selector(...)' CSS function into the CSS.supports() method with the selector for
// which we're assessing support:
if (!CSS.supports('selector(:has(input:valid))')) {
  const hasValue = (evt) => {
      let target = evt.currentTarget;
      target.closest('.wrapper').classList.toggle('childInputHasValue', target.validity.valid);
    },
    inputs = document.querySelectorAll('input[type=text]');

  inputs.forEach(
    (el) => el.addEventListener('input', hasValue)
  );
}
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.placeholder {
  color: crimson;
}

/* this selector will be used by browsers that understand, and
   implement, the ':has(...)' selector, and discarded by others: */
.wrapper:has(input:valid)   .placeholder {
  color: lime;
}

/* this selector will take advantage of the classes/approach
   implemented by JavaScript: */
.wrapper.childInputHasValue   .placeholder {
  color: lime;
}
<div >
  <input type="text" required pattern="^[a-zA-Z0-9][a-zA-Z0-9\s]{5,20}$">
</div>
<span >E-Mail</span>

JS Fiddle demo.

References:

  • Related