सीएसएस और स्टाइल
इस लेख में, शैडो डीओएम की मदद से की जा सकने वाली ज़्यादा शानदार चीज़ों के बारे में बताया गया है. यह उन कॉन्सेप्ट पर आधारित होता है जिनके बारे में Shadow DOM 101 में चर्चा की गई है. अगर आपको इस बारे में जानकारी चाहिए, तो वह लेख पढ़ें.
परिचय
आइए, स्वीकार करें. स्टाइल न किए गए मार्कअप में कोई खास बात नहीं होती. हमारे लिए खुशी की बात है कि वेब कॉम्पोनेंट के पीछे काम करने वाले शानदार लोग ने इस बात का पहले ही अनुमान लगा लिया था और हमें इस समस्या से निजात दिलाने के लिए काम करना शुरू कर दिया था. सीएसएस स्कोपिंग मॉड्यूल, शैडो ट्री में कॉन्टेंट को स्टाइल करने के कई विकल्पों के बारे में बताता है.
स्टाइल एनकैप्सुलेशन
शैडो डीओएम की मुख्य सुविधाओं में से एक शैडो बाउंड्री है. इसमें कई अच्छी प्रॉपर्टी हैं, लेकिन सबसे अच्छी बात यह है कि यह स्टाइल को मुफ़्त में एन्कैप्सुलेट करता है. दूसरे शब्दों में कहें, तो:
<div><h3>Light DOM</h3></div>
<script>
var root = document.querySelector('div').createShadowRoot();
root.innerHTML = `
<style>
h3 {
color: red;
}
</style>
<h3>Shadow DOM</h3>
`;
</script>
इस डेमो के बारे में दो दिलचस्प बातें हैं:
- इस पेज पर अन्य h3 एलिमेंट भी हैं, लेकिन सिर्फ़ ShadowRoot में मौजूद एलिमेंट, h3 सिलेक्टर से मैच करता है. इसलिए, उसे लाल रंग में स्टाइल किया गया है. फिर से, डिफ़ॉल्ट रूप से दायरे वाली स्टाइल.
- इस पेज पर बताए गए अन्य स्टाइल नियम, h3 को टारगेट करते हैं. ये मेरे कॉन्टेंट में ब्लीड नहीं होते. ऐसा इसलिए होता है, क्योंकि सैलेक्टर, शैडो की सीमा को पार नहीं करते.
कहानी का मतलब क्या है? हम बाहरी दुनिया से स्टाइल को अलग रखते हैं. धन्यवाद, शैडो डीओएम!
होस्ट एलिमेंट का लुक तय करना
:host
की मदद से, शैडो ट्री को होस्ट करने वाले एलिमेंट को चुना और स्टाइल किया जा सकता है:
<button class="red">My Button</button>
<script>
var button = document.querySelector('button');
var root = button.createShadowRoot();
root.innerHTML = `
<style>
:host {
text-transform: uppercase;
}
</style>
<content></content>
`;
</script>
एक बात ध्यान रखें कि पैरंट पेज के नियम, एलिमेंट में तय किए गए :host
नियमों से ज़्यादा खास होते हैं. हालांकि, ये होस्ट एलिमेंट पर तय किए गए style
एट्रिब्यूट से कम खास होते हैं. इससे उपयोगकर्ता, बाहर से आपकी स्टाइल को बदल सकते हैं.
:host
सिर्फ़ ShadowRoot के कॉन्टेक्स्ट में भी काम करता है, इसलिए इसे Shadow DOM के बाहर इस्तेमाल नहीं किया जा सकता.
:host(<selector>)
का फ़ंक्शनल फ़ॉर्म, आपको होस्ट एलिमेंट को टारगेट करने की अनुमति देता है, अगर वह <selector>
से मेल खाता है.
उदाहरण - सिर्फ़ तब मैच करें, जब एलिमेंट में क्लास .different
(उदाहरण के लिए, <x-foo class="different"></x-foo>
) हो:
:host(.different) {
...
}
उपयोगकर्ता की स्थितियों पर प्रतिक्रिया देना
:host
का इस्तेमाल आम तौर पर तब किया जाता है, जब कोई कस्टम एलिमेंट बनाया जा रहा हो और आपको उपयोगकर्ता की अलग-अलग स्थितियों (:hover, :focus, :active वगैरह) पर प्रतिक्रिया देनी हो.
<style>
:host {
opacity: 0.4;
transition: opacity 420ms ease-in-out;
}
:host(:hover) {
opacity: 1;
}
:host(:active) {
position: relative;
top: 3px;
left: 3px;
}
</style>
किसी एलिमेंट को थीम के हिसाब से बनाना
:host-context(<selector>)
स्यूडो क्लास, होस्ट एलिमेंट से मेल खाती है, अगर वह या उसका कोई भी पैरंट एलिमेंट <selector>
से मेल खाता है.
:host-context()
का आम तौर पर इस्तेमाल, किसी एलिमेंट के आस-पास मौजूद एलिमेंट के आधार पर, उस एलिमेंट की थीम तय करने के लिए किया जाता है. उदाहरण के लिए, कई लोग <html>
या <body>
पर कोई क्लास लागू करके थीमिंग करते हैं:
<body class="different">
<x-foo></x-foo>
</body>
जब <x-foo>
, क्लास .different
वाले एलिमेंट का वंशज हो, तो <x-foo>
को स्टाइल करने के लिए :host-context(.different)
का इस्तेमाल किया जा सकता है:
:host-context(.different) {
color: red;
}
इससे, किसी एलिमेंट के शैडो डीओएम में स्टाइल नियमों को शामिल किया जा सकता है. ये नियम, एलिमेंट के कॉन्टेक्स्ट के आधार पर, उसे यूनीक स्टाइल देते हैं.
एक शैडो रूट में, कई तरह के होस्ट के साथ काम करता है
:host
का इस्तेमाल, थीम वाली लाइब्रेरी बनाने के लिए भी किया जा सकता है. साथ ही, एक ही शैडो DOM में कई तरह के होस्ट एलिमेंट को स्टाइल करने के लिए भी किया जा सकता है.
:host(x-foo) {
/* Applies if the host is a <x-foo> element.*/
}
:host(x-foo:host) {
/* Same as above. Applies if the host is a <x-foo> element. */
}
:host(div) {
/* Applies if the host element is a <div>. */
}
शैडो डीओएम के अंदरूनी एलिमेंट को बाहर से स्टाइल करना
::shadow
स्यूडो-एलिमेंट और /deep/
कॉम्बिनेटर, सीएसएस के लिए एक तरह से तलवार की तरह हैं.
इनकी मदद से, शैडो डीओएम की सीमा को पार करके, शैडो ट्री में मौजूद एलिमेंट को स्टाइल किया जा सकता है.
::shadow स्यूडो-एलिमेंट
अगर किसी एलिमेंट में कम से कम एक शैडो ट्री है, तो ::shadow
स्यूडो-एलिमेंट खुद शैडो रूट से मैच करता है.
इससे, ऐसे सिलेक्टर लिखे जा सकते हैं जो किसी एलिमेंट के शैडो डॉम में मौजूद नोड को स्टाइल करते हैं.
उदाहरण के लिए, अगर कोई एलिमेंट शैडो रूट होस्ट कर रहा है, तो उसके शैडो ट्री के सभी स्पैन को स्टाइल देने के लिए #host::shadow span {}
लिखा जा सकता है.
<style>
#host::shadow span {
color: red;
}
</style>
<div id="host">
<span>Light DOM</span>
</div>
<script>
var host = document.querySelector('div');
var root = host.createShadowRoot();
root.innerHTML = `
<span>Shadow DOM</span>
<content></content>
`;
</script>
उदाहरण (कस्टम एलिमेंट) - <x-tabs>
के शैडो DOM में <x-panel>
चाइल्ड हैं. हर पैनल में अपना शैडो ट्री होता है, जिसमें h2
हेडिंग होती हैं. मुख्य पेज पर मौजूद उन हेडलाइन को स्टाइल करने के लिए, यह लिखा जा सकता है:
x-tabs::shadow x-panel::shadow h2 {
...
}
/डीप/ कॉम्बिनेटर
/deep/
कॉम्बिनेटर, ::shadow
जैसा ही होता है, लेकिन ज़्यादा असरदार होता है. यह सभी शैडो बॉर्डर को पूरी तरह से अनदेखा करता है और किसी भी संख्या में शैडो ट्री को पार करता है. आसान शब्दों में कहें, तो /deep/
आपको किसी एलिमेंट के दिमाग में ड्रिल करने और किसी नोड को टारगेट करने की सुविधा देता है.
/deep/
कॉम्बिनेटर, कस्टम एलिमेंट के लिए खास तौर पर मददगार होता है. कस्टम एलिमेंट में, शैडो डीओएम के कई लेवल होते हैं. इसके मुख्य उदाहरण हैं, कस्टम एलिमेंट का एक ग्रुप नेस्ट करना (हर एलिमेंट अपना शैडो ट्री होस्ट करता है) या <shadow>
का इस्तेमाल करके, ऐसा एलिमेंट बनाना जो किसी दूसरे एलिमेंट से इनहेरिट होता है.
उदाहरण (कस्टम एलिमेंट) - ट्री में कहीं भी, <x-tabs>
के वंशज सभी <x-panel>
एलिमेंट चुनें:
x-tabs /deep/ x-panel {
...
}
उदाहरण - शैडो ट्री में कहीं भी, क्लास .library-theme
वाले सभी एलिमेंट को स्टाइल करें:
body /deep/ .library-theme {
...
}
querySelector() का इस्तेमाल करना
जिस तरह .shadowRoot
, डीओएम को ट्रैवर्स करने के लिए शैडो ट्री खोलता है उसी तरह कॉम्बिनेटर, सिलेक्टर को ट्रैवर्स करने के लिए शैडो ट्री खोलते हैं.
पागलपन की एक सीरीज़ लिखने के बजाय, आप एक वाक्य लिख सकते हैं:
// No fun.
document.querySelector('x-tabs').shadowRoot
.querySelector('x-panel').shadowRoot
.querySelector('#foo');
// Fun.
document.querySelector('x-tabs::shadow x-panel::shadow #foo');
नेटिव एलिमेंट को स्टाइल करना
स्टाइल के हिसाब से नेटिव एचटीएमएल कंट्रोल बनाना मुश्किल होता है. कई लोग इस प्रोसेस को छोड़ देते हैं और खुद ही रोल करते हैं. हालांकि, ::shadow
और /deep/
की मदद से, वेब प्लैटफ़ॉर्म पर मौजूद किसी भी ऐसे एलिमेंट को स्टाइल किया जा सकता है जो शैडो डीओएम का इस्तेमाल करता है. <input>
टाइप और <video>
के उदाहरण:
video /deep/ input[type="range"] {
background: hotpink;
}
किसी स्टाइल को अपनाना
कस्टमाइज़ेशन अच्छा है. कुछ मामलों में, हो सकता है कि आप अपनी Shadow के स्टाइलिंग शील्ड में छेद करना चाहें और दूसरों की स्टाइल के लिए हुक बनाना चाहें.
::shadow और /deep/ का इस्तेमाल करना
/deep/
बहुत ज़्यादा काम का है. इससे कॉम्पोनेंट बनाने वाले लोगों को, अलग-अलग एलिमेंट को स्टाइल करने के लिए या कई एलिमेंट को थीम के तौर पर इस्तेमाल करने के लिए तय करने का विकल्प मिलता है.
उदाहरण - सभी शैडो ट्री को अनदेखा करते हुए, उन सभी एलिमेंट को स्टाइल करें जिनमें क्लास .library-theme
है:
body /deep/ .library-theme {
...
}
कस्टम स्यूडो एलिमेंट का इस्तेमाल करना
WebKit और
Firefox, दोनों नेटिव ब्राउज़र एलिमेंट के इंटरनल हिस्सों को स्टाइल करने के लिए, स्यूडो एलिमेंट तय करते हैं. input[type=range]
इसका एक अच्छा उदाहरण है. आपके पास ::-webkit-slider-thumb
को टारगेट करके, स्लाइडर को <span style="color:blue">blue</span>
की स्टाइल करने का विकल्प है:
input[type=range].custom::-webkit-slider-thumb {
-webkit-appearance: none;
background-color: blue;
width: 10px;
height: 40px;
}
ब्राउज़र कुछ इंटरनल में स्टाइलिंग हुक की सुविधा देते हैं. इसी तरह, शैडो डीओएम कॉन्टेंट के लेखक कुछ एलिमेंट को ऐसे तय कर सकते हैं जिन्हें बाहरी लोग स्टाइल कर सकें. ऐसा करने के लिए, कस्टम स्यूडो एलिमेंट का इस्तेमाल किया जाता है.
pseudo
एट्रिब्यूट का इस्तेमाल करके, किसी एलिमेंट को कस्टम स्यूडो एलिमेंट के तौर पर सेट किया जा सकता है.
इसके मान या नाम के आगे "x-" लगाना ज़रूरी है. ऐसा करने से शैडो ट्री में उस एलिमेंट के साथ एक जुड़ाव बन जाता है और बाहरी लोगों को शैडो सीमा पार करने के लिए एक तय लेन मिल जाता है.
यहां एक कस्टम स्लाइडर विजेट बनाने और किसी व्यक्ति को स्लाइडर थंब ब्लू को स्टाइल करने की अनुमति देने का एक उदाहरण दिया गया है:
<style>
#host::x-slider-thumb {
background-color: blue;
}
</style>
<div id="host"></div>
<script>
var root = document.querySelector('#host').createShadowRoot();
root.innerHTML = `
<div>
<div pseudo="x-slider-thumb"></div>' +
</div>
`;
</script>
सीएसएस वैरिएबल का इस्तेमाल करना
सीएसएस वैरिएबल की मदद से, थीम वाले हुक बनाने का बेहतरीन तरीका है. इसका मतलब है कि अन्य उपयोगकर्ताओं के लिए "स्टाइल प्लेसहोल्डर" बनाना, ताकि वे उन्हें भर सकें.
मान लें कि कस्टम एलिमेंट बनाने वाला कोई ऐसा व्यक्ति है जो अपने शैडो डीओएम में वैरिएबल प्लेसहोल्डर को मार्क करता है. एक बटन के फ़ॉन्ट को स्टाइल करने के लिए और दूसरा रंग के लिए:
button {
color: var(--button-text-color, pink); /* default color will be pink */
font-family: var(--button-font);
}
इसके बाद, एलिमेंट को जोड़ने वाला व्यक्ति अपनी पसंद के मुताबिक उन वैल्यू को तय करता है. शायद, अपने पेज की सुपर कूल कॉमिक सैन्स थीम से मैच करने के लिए:
#host {
--button-text-color: green;
--button-font: "Comic Sans MS", "Comic Sans", cursive;
}
सीएसएस वैरिएबल के इनहेरिट होने के तरीके की वजह से, सब कुछ ठीक है और यह बेहतरीन तरीके से काम करता है! पूरी तस्वीर कुछ ऐसी दिखती है:
<style>
#host {
--button-text-color: green;
--button-font: "Comic Sans MS", "Comic Sans", cursive;
}
</style>
<div id="host">Host node</div>
<script>
var root = document.querySelector('#host').createShadowRoot();
root.innerHTML = `
<style>
button {
color: var(--button-text-color, pink);
font-family: var(--button-font);
}
</style>
<content></content>
`;
</script>
शैलियों को रीसेट किया जा रहा है
फ़ॉन्ट, रंग, और लाइन-हाइट जैसी इनहेरिट की जा सकने वाली स्टाइल का, शैडो DOM में मौजूद एलिमेंट पर असर पड़ता रहता है. हालांकि, ज़्यादा सुविधाओं के लिए, शैडो DOM हमें resetStyleInheritance
प्रॉपर्टी देता है, ताकि हम शैडो की सीमा पर होने वाली चीज़ों को कंट्रोल कर सकें.
इसे नया कॉम्पोनेंट बनाते समय, एक नई शुरुआत करने के तरीके के तौर पर देखें.
resetStyleInheritance
false
- डिफ़ॉल्ट. इनहेरिट की जा सकने वाली सीएसएस प्रॉपर्टी इनहेरिट की जाती हैं.true
- इनहेरिट की जा सकने वाली प्रॉपर्टी को बॉर्डर परinitial
पर रीसेट करता है.
यहां एक डेमो दिया गया है, जिसमें दिखाया गया है कि resetStyleInheritance
में बदलाव करने से, शैडो ट्री पर क्या असर पड़ता है:
<div>
<h3>Light DOM</h3>
</div>
<script>
var root = document.querySelector('div').createShadowRoot();
root.resetStyleInheritance = <span id="code-resetStyleInheritance">false</span>;
root.innerHTML = `
<style>
h3 {
color: red;
}
</style>
<h3>Shadow DOM</h3>
<content select="h3"></content>
`;
</script>
<div class="demoarea" style="width:225px;">
<div id="style-ex-inheritance"><h3 class="border">Light DOM</div>
</div>
<div id="inherit-buttons">
<button id="demo-resetStyleInheritance">resetStyleInheritance=false</button>
</div>
<script>
var container = document.querySelector('#style-ex-inheritance');
var root = container.createShadowRoot();
//root.resetStyleInheritance = false;
root.innerHTML = '<style>h3{ color: red; }</style><h3>Shadow DOM<content select="h3"></content>';
document.querySelector('#demo-resetStyleInheritance').addEventListener('click', function(e) {
root.resetStyleInheritance = !root.resetStyleInheritance;
e.target.textContent = 'resetStyleInheritance=' + root.resetStyleInheritance;
document.querySelector('#code-resetStyleInheritance').textContent = root.resetStyleInheritance;
});
</script>
.resetStyleInheritance
को समझना थोड़ा मुश्किल है. इसकी खास वजह यह है कि इसका असर सिर्फ़ इनहेरिट की जा सकने वाली सीएसएस प्रॉपर्टी पर पड़ता है. इसमें बताया गया है कि जब आपको पेज और शैडो रूट के बीच की सीमा पर, इनहेरिट करने के लिए कोई प्रॉपर्टी चाहिए, तो होस्ट से वैल्यू इनहेरिट न करें. इसके बजाय, सीएसएस स्पेसिफ़िकेशन के मुताबिक initial
वैल्यू का इस्तेमाल करें.
अगर आपको नहीं पता कि सीएसएस में कौनसी प्रॉपर्टी इनहेरिट होती हैं, तो यह आसान सूची देखें या एलिमेंट पैनल में "इनहेरिट की गई प्रॉपर्टी दिखाएं" चेकबॉक्स को टॉगल करें.
वितरित नोड को शैली देना
डिस्ट्रिब्यूट किए गए नोड ऐसे एलिमेंट होते हैं जो शामिल करने के पॉइंट (<content>
एलिमेंट) पर रेंडर होते हैं. <content>
एलिमेंट की मदद से, लाइट डीओएम से नोड चुने जा सकते हैं और उन्हें अपने शैडो डीओएम में पहले से तय की गई जगहों पर रेंडर किया जा सकता है. ये शैडो डीओएम में लॉजिकल तरीके से काम नहीं करते हैं; वे अब भी होस्ट एलिमेंट के चाइल्ड हैं. इंसर्शन पॉइंट, रेंडरिंग के लिए होते हैं.
डिस्ट्रिब्यूट किए गए नोड, मुख्य दस्तावेज़ की स्टाइल को बनाए रखते हैं. इसका मतलब है कि मुख्य पेज के स्टाइल के नियम, एलिमेंट पर लागू होते रहते हैं, भले ही वे किसी इंसर्शन पॉइंट पर रेंडर होते हों. फिर से, वितरित नोड अभी भी प्रकाश बिंदु में तार्किक रूप से होते हैं और हिलते नहीं हैं. ये सिर्फ़ कहीं और रेंडर होते हैं. हालांकि, जब नोड शैडो डीओएम में बांट दिए जाते हैं, तो वे शैडो ट्री में तय किया गया अतिरिक्त स्टाइल इस्तेमाल कर सकते हैं.
::content स्यूडो एलिमेंट
डिस्ट्रिब्यूट किए गए नोड, होस्ट एलिमेंट के चाइल्ड होते हैं. इसलिए, हम शैडो डीओएम के अंदर से उन्हें कैसे टारगेट कर सकते हैं? इसका जवाब है, सीएसएस ::content
सूडो एलिमेंट.
यह ऐसे लाइट डीओएम नोड को टारगेट करने का तरीका है जो इंसर्शन पॉइंट से होकर गुज़रते हैं. उदाहरण के लिए:
::content > h3
, ऐसे किसी भी h3
टैग को स्टाइल करता है जो इंसर्शन पॉइंट से गुज़रता है.
आइए, एक उदाहरण देखें:
<div>
<h3>Light DOM</h3>
<section>
<div>I'm not underlined</div>
<p>I'm underlined in Shadow DOM!</p>
</section>
</div>
<script>
var div = document.querySelector('div');
var root = div.createShadowRoot();
root.innerHTML = `
<style>
h3 { color: red; }
content[select="h3"]::content > h3 {
color: green;
}
::content section p {
text-decoration: underline;
}
</style>
<h3>Shadow DOM</h3>
<content select="h3"></content>
<content select="section"></content>
`;
</script>
शामिल करने के पॉइंट पर स्टाइल रीसेट करना
ShadowRoot बनाते समय, आपके पास इनहेरिट की गई स्टाइल को रीसेट करने का विकल्प होता है.
<content>
और <shadow>
इंसर्शन पॉइंट में भी यह विकल्प होता है. इन एलिमेंट का इस्तेमाल करते समय, JS में .resetStyleInheritance
सेट करें या एलिमेंट पर बोलियन reset-style-inheritance
एट्रिब्यूट का इस्तेमाल करें.
ShadowRoot या
<shadow>
इंसर्शन पॉइंट के लिए:reset-style-inheritance
का मतलब है कि इनहेरिट की जा सकने वाली सीएसएस प्रॉपर्टी, होस्ट परinitial
पर सेट होती हैं. ऐसा, आपके शैडो कॉन्टेंट में शामिल होने से पहले होता है. इस जगह को ऊपरी सीमा कहा जाता है.<content>
इंसर्शन पॉइंट के लिए:reset-style-inheritance
का मतलब है कि इनहेरिट की जा सकने वाली सीएसएस प्रॉपर्टी कोinitial
पर सेट किया जाता है. ऐसा, होस्ट के चाइल्ड को इंसर्शन पॉइंट पर बांटने से पहले किया जाता है. इस जगह को निचली सीमा कहा जाता है.
नतीजा
कस्टम एलिमेंट के लेखक के तौर पर, हमारे पास अपने कॉन्टेंट के लुक और स्टाइल को कंट्रोल करने के लिए कई विकल्प होते हैं. शैडो डीओएम, इस नई दुनिया का आधार है.
शैडो DOM की मदद से, स्टाइल को स्कोप में रखा जा सकता है. साथ ही, बाहरी दुनिया को ज़रूरत के मुताबिक (ज़्यादा या कम) शामिल किया जा सकता है. कस्टम स्यूडो एलिमेंट तय करके या सीएसएस वैरिएबल प्लेसहोल्डर शामिल करके, लेखक तीसरे पक्ष को स्टाइल करने के लिए आसान हुक दे सकते हैं, ताकि वे अपने कॉन्टेंट को ज़्यादा पसंद के मुताबिक बना सकें. कुल मिलाकर, वेब लेखकों के पास यह तय करने का पूरा कंट्रोल होता है कि उनके कॉन्टेंट को कैसे दिखाया जाए.