How can I target class inside shadow root without JS? - html

Let's say I have html element with shadow root.
<my-element>
#shadow-root
<div class='need-target-this' />
</my-element>
How can I target div inside shadow root?
I've tried to use
:host(my-element.need-target-this)
But it didn't help. What am I missing here?

Style shadowDOM with <style> tags inside shadowDOM
also see ::part: https://developer.mozilla.org/en-US/docs/Web/CSS/::part
also see: ::slotted CSS selector for nested children in shadowDOM slot
customElements.define("my-element",class extends HTMLElement{
constructor(){
super().attachShadow({mode:"open"}).innerHTML = `
<style>
.target { background:hotpink; border: 5px dashed green }
::slotted(span) {
color : red;
}
</style>
<slot name="title"></slot>
<span part="mytarget" class='target' />`;
}
connectedCallback(){
this.shadowRoot.querySelector("span").innerHTML = `Web Component!`;
}
});
<style>
* { font: 42px Arial }
span {
background:gold; /* slot content styled by Global CSS! */
}
.target { border: 5px solid blue } /* does NOT style shadowDOM! */
my-element::part(mytarget) {
font-size: 150%;
}
</style>
<my-element class="target"><span slot="title">Hello</span>
</my-element>

In case it will help some one: I wrapped my element with div added ref and then went
const shadow = ref.current.querySelector('my-element').shadowRoot
const target = shadow?.querySelector('.need-target-this')
target.style.whatever = 'value';

Related

Change another Tag Css When input Has Value

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 class="wrapper">
<input type="text" required>
</div>
<span class="placeholder">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;
}
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 class="wrapper">
<input type="text" required pattern="^[a-zA-Z0-9][a-zA-Z0-9\s]{5,20}$">
</div>
<span class="placeholder">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 class="wrapper">
<input type="text" required pattern="^[a-zA-Z0-9][a-zA-Z0-9\s]{5,20}$">
<span class="placeholder">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 class="wrapper">
<input type="text" required pattern="^[a-zA-Z0-9][a-zA-Z0-9\s]{5,20}$">
</div>
<span class="placeholder">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 class="wrapper">
<input type="text" required pattern="^[a-zA-Z0-9][a-zA-Z0-9\s]{5,20}$">
</div>
<span class="placeholder">E-Mail</span>
JS Fiddle demo.
References:
CSS:
Adjacent-sibling (+) combinator.
:has() (compatibility).
#supports.
HTML:
pattern attribute.
required attribute.
JavaScript:
Arrow functions.
CSS.supports().
document.querySelectorAll().
Element.classList.
Element.closest().
EventTarget.addEventListener().
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;
}

Applying CSS to Polymer custom element with iron-media-query

I'm trying to achieve a simple 'media-query' behavior on my custom element using <iron-media-query> from the Polymer API.
Assume i have a container with some text on top the top, and below it is the main content..
My goal is to write media queries so that when the element is displayed on a big screen (just bigger than 768px for my testing), i can do some simple margin and padding modifications to the elements local DOM styles.
I just can't make it work.
Is there something i completely missed here ?
<link rel="import" href="../../bower_components/polymer/polymer.html"/>
<link rel="import" href="../../bower_components/iron-media-query/iron-media-query.html" />
<iron-media-query query="(max-width:768px)" query-matches="{{isMobilePhone}}"></iron-media-query>
<template is="dom-if" if="{{isMobilePhone}}">
<style>
#title {
color: #000000;
font-size: 1.8em;
}
</style>
</template>
<template>
<style>
:host {
background-color: gray;
flex-direction: column;
margin: auto;
margin-top: 40px;
display: flex;
width: 90%;
flex-grow: 1;
max-width: 1300px;
}
#title {
color: #7DB8C9;
font-size: 1.3em;
}
.content-wrapper {
height: 100%;
}
</style>
<p id="title">
[[title]]
</p>
<div class="content-wrapper">
<content select=".content"></content>
</div>
</template>
<script>
Polymer({
is: 'content-container',
properties: {
title: String,
isMobilePhone: Boolean
},
listeners: {
'tap': 'spit'
},
spit: function() {
console.log("BOOL: " + this.isMobilePhone);
}
});
</script> </dom-module>
I also tried copying the whole template ( with styles and markup ) inside the 'if' template and just modify the styles i want, but it doesn't work either.
(Everything is inside the same file, which is content-container.html)
One of the easiest ways to achieve this (which is the one used in the iron-media-query demo) is to use Polymer's annotated attribute bindings together with attribute selectors.
A simple example of an element's template would look like this
<template>
<style>
.content-wrapper ::content {
color: blue;
}
.content-wrapper[mobile-layout] ::content {
color: green;
}
</style>
<iron-media-query query="(max-width:768px)" query-matches="{{isMobilePhone}}"></iron-media-query>
<div class="content-wrapper" mobile-layout$="[[isMobilePhone]]">
<content></content>
</div>
</template>
Here's a fiddle showing it in action
<style> tags anywhere inside a <dom-module> (even dom-if) are applied to the element immediately (as seen in this demo), so putting <style> inside a dom-if would not give you conditional styles.
And if the only purpose of using <iron-media-query> was to add a conditional <style>, you don't need the element at all. Just use the media query normally in CSS:
<style>
...
#title {
color: #7DB8C9;
font-size: 1.3em;
}
#media (max-width:768px) {
#title {
color: #000000;
font-size: 1.8em;
}
}
</style>
codepen

Change img src on hover

How do I create an url link prefixed with a small thumbnail-image, such that when I hover on them, BOTH the link color and the thumbnail-image change
Example:
Im now using an image tag that goes with an anchor tag, Im able to change the anchor tag text color on hover, however I dont know how to change the img src accordingly
CSS:
.hoverable-link {
color: gray;
}
.hoverable-link:hover {
color: blue;
}
HTML:
<div>
<img src="thumbnail-1"> //Change to thumbnail-2
Cool Link
</div>
JsFiddle: https://jsfiddle.net/rbb5ow1v/9/
In conclusion:
[1] How can I change img src when it's on hover
[2] How can I trigger hover-event for both element at the same time
I would give fontello.com a go
Once you have chosen the desired icons set up your tag as follows
<span class="icon-twitter"></span>example
When you do the CSS you just have to apply a hover state to the anchor and because of fontello it will change that colour too by just using the CSS color attribute.
EDIT:
If you are using a specific twitter icon that you made. Try changing it to an SVG, and change its fill. Same can be applied to the fontello where you can display none and reveal on hovers.
[1] How can I change img src when it's on hover
You can't do this with CSS alone, as src is a DOM attribute not a CSS attribute, to accomplish this some javascript is required with HTML DOM Event system
<body>
<div>
<img onmouseenter="highlight(this)" onmouseleave="unhighlight(this)"
src="thumbnail1">
Some Link
</div>
<script>
function highlight(image) {
image.src = "thumbnail2"; //Blue Image
}
function unhighlight(image) {
image.src = "thumbnail1"; //Gray Image
}
</script>
</body>
JsFiddle: https://jsfiddle.net/f0c7p3tL/2/
List of DOM Events: http://www.w3schools.com/jsref/dom_obj_event.asp
Another approach is to not using the src DOM attribute at all. Instead you can use the background CSS attribute, that way you can utilize the CSS:hover selector
CSS:
#my-thumbnail {
background: url("/thumbnail1") no-repeat;
width: 32px;
height: 32px;
}
#my-thumbnail:hover {
background: url("/thumbnail2") no-repeat;
}
HTML:
<div>
<img id="my-thumbnail">
Some Link
</div>
JsFiddle: https://jsfiddle.net/7xoprwky/
[2] How can I trigger hover-event for both element at the same time
Again, two approaches are available here.
First is using javascript and the HTML DOM Events. In this approach, instead of triggering events on either of the child elements, we want them to be triggered on the surrounding <div> parent element. Then, in the event handler, we select the child elements and change their DOM Attribute accordingly
<body>
<div onmouseenter="highlight(this)" onmouseleave="unhighlight(this)">
<img id="my-thumbnail" src="thumbnail1">
<a id="my-anchor" href="#potato">Some Link</a>
</div>
<script>
var myThumbnail = document.getElementById('my-thumbnail'),
myAnchor = document.getElementById('my-anchor');
function highlight() {
myThumbnail.src = "/thumbnail2";
myAnchor.style.color = "blue";
myAnchor.style.fontWeight = "bold";
}
function unhighlight() {
myThumbnail.src = "/thumbnail1";
myAnchor.style.color = "gray";
myAnchor.style.fontWeight = "normal";
}
</script>
</body>
JsFiddle: https://jsfiddle.net/2uthconL/
In the second approach we utilize the CSS selector syntax to highlight our internal element from our surrounding div
CSS:
#my-thumbnail-link {
}
#my-thumbnail-link img { /* Select all img tag inside div */
background: url("/thumbnail1") no-repeat;
width: 32px;
height: 32px;
}
#my-thumbnail-link:hover img { /* Select all img tag inside div when it is hovered */
background: url("/thumbnail2") no-repeat;
}
#my-thumbnail-link a { /* Select all a tag inside div */
color: gray;
}
#my-thumbnail-link:hover a { /* Select all a tag inside div when it is hovered */
color: blue;
font-weight: bold;
}
HTML:
<div id="my-thumbnail-link" class="vcenter-parent">
<img class="vcenter-child">
Some Link
</div>
JsFiddle: https://jsfiddle.net/x61dy0mk/2/
More on CSS Selector: http://www.w3schools.com/cssref/css_selectors.asp
If your thumbnail is just a static asset, I recommend the CSS approach over the Javascript HTML DOM one for its readability and maintainability (imagine keeping thousands of event handlers)
maybe you can try this one:
html
css for styling
.twitterbird {
margin-bottom: 10px;
width: 160px;
height:160px;
display:block;
background:transparent url('twitterbird.png') center top no-repeat;
}
.twitterbird:hover {
background-image: url('twitterbird_hover.png');
}
this answer is based on this question CSS: image link, change on hover
Update - Just try this one:
html
<ul>
<li><a id="hoverable" href="#"><i class="home-icon"></i><span class="text">Link 1</span></a></li>
<li><a id="hoverable" href="#"><i class="tshirt-icon"></i><span class="text">Link 2</span></a></li>
</ul>
css
a {
color: black;
text-decoration: none;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
.home-icon {
background: url("http://s1.postimg.org/gk5fbl6vv/home_black.png") no-repeat;
width: 32px;
height: 32px;
display: inline-block;
margin-right: 20px;
}
a:hover .home-icon {
background: url("http://s2.postimg.org/43870q29h/home_green.png") no-repeat;
}
.tshirt-icon {
background: url("http://s30.postimg.org/61bqc12fh/tshirt_black.png") no-repeat;
width: 32px;
height: 32px;
display: inline-block;
margin-right: 20px;
}
a:hover .tshirt-icon {
background: url("http://s17.postimg.org/3x9qzn8sb/tshirt_green.png") no-repeat;
}
a#hoverable:hover {
color: green;
font-weight: bold;
}
demo is on this link https://jsfiddle.net/nv4dw8vr/

Can't apply styles to dynamically created nodes

I created a custom element and I take html from its <content> and on created I use Polymer.dom(this.root).appendChild(paperItem) (paperItem was created via iteration on HTML I'd received from <content>) to insert that into local DOM. Well, I can't style <paper-item> from template's <style> tag no matter what I do. Even Polymer.updateStyles(); doesn't help. What am I getting wrongly?
Here explain how to apply styles to distributed children.
<dom-module id="my-element">
<template>
<style>
:host {
display: block;
border: 1px solid red;
}
#child-element {
background: yellow;
}
/* styling elements distributed to content (via ::content) requires */
/* selecting the parent of the <content> element for compatibility with */
/* shady DOM . This can be :host or a wrapper element. */
.content-wrapper > ::content .special {
background: orange;
}
</style>
<div id="child-element">In local DOM!</div>
<div class="content-wrapper"><content></content></div>
</template>
<script>
Polymer({
is: 'my-element'
});
</script>
</dom-module>
<my-element>
<div class="special">Here will have a different css </div>
</my-element>

CSS - Manipulate another element on hover

I need to change #hidden to display:block when #aaa is hovered over. It's not working because #aaa isn't on the same level as #hidden - is there a way to manipulate a completely separate element on hover? I'm trying to make a CSS-based nav w/ a subnav and show the respective subnav when a nav item is hovered over.
HTML:
<div class="cheetahContainer">
<div id="cheetah">
<p>Cheetah</p>
</div>
</div>
<div id="hidden">
<p>A cheetah is a land mammal that can run up 2 60mph!!!</p>
</div>
CSS:
#cheetah {
background-color: red;
text-align: center;
}
a {
color: blue;
}
#hidden {
display:none;
color: orange;
}
#cheetah:hover{
background-color:green;
}
#cheetah:hover + #hidden {
display:block;
}
http://jsfiddle.net/LgKkU/575/
Since your link is not a sibling of your #hidden div (thus you can't use the immediate adjacency selector), you should change last rule with
.cheetahContainer:hover + #hidden {
display:block;
}
Hovering over an element can only affect child elements in css. Here's a fix for your example:
<div class="cheetahContainer">
<div id="cheetah">
<p>Cheetah</p>
</div>
<div id="hidden">
<p>A cheetah is a land mammal that can run up 2 60mph!!!</p>
</div>
</div>
However, I would recommend changing the css to something like this:
.cheetahContainer:hover .hidden {
display: block;
}
Changed out id's for classes and added hover to parent element so that hovering over the revealed text doesn't revert back to display:none;
It is not a direct sibling so you need to use js
Here is an example of what to do:
var $cheetah = document.getElementById('cheetah');
var $hidden = document.getElementById('hidden');
$cheetah.addEventListener('mouseover', function() {
$hidden.style.display = 'block';
});
$cheetah.addEventListener('mouseout', function() {
$hidden.style.display = 'none';
});
Or you can use the container:
.cheetarContainer:hover + #hidden {
display: block;
}