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>
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>
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>
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>
References: