ডিজাইন সিস্টেম ও কম্পোনেন্ট লাইব্রেরিতে কাস্টম প্রপার্টি ব্যবহার করার সুবিধা।
আমি ডেভ এবং আমি Nordhealth-এ একজন সিনিয়র ফ্রন্ট-এন্ড ডেভেলপার। আমি আমাদের ডিজাইন সিস্টেম Nord-এর ডিজাইন ও ডেভেলপমেন্টের কাজ করি, যার মধ্যে আমাদের কম্পোনেন্ট লাইব্রেরির জন্য ওয়েব কম্পোনেন্ট তৈরি করাও অন্তর্ভুক্ত। আমি শেয়ার করতে চাই যে CSS কাস্টম প্রপার্টি ব্যবহার করে ওয়েব কম্পোনেন্ট স্টাইল করার সময় আমরা কীভাবে সমস্যার সমাধান করেছি এবং ডিজাইন সিস্টেম ও কম্পোনেন্ট লাইব্রেরিতে কাস্টম প্রপার্টি ব্যবহার করার অন্যান্য কিছু সুবিধা।
আমরা কীভাবে ওয়েব কম্পোনেন্ট তৈরি করি
আমাদের ওয়েব কম্পোনেন্ট তৈরি করতে আমরা Lit ব্যবহার করি, এটি এমন একটি লাইব্রেরি যা স্টেট, স্কোপড স্টাইল, টেমপ্লেটিং এবং আরও অনেক কিছুর মতো প্রচুর বয়লারপ্লেট কোড প্রদান করে। Lit শুধু লাইটওয়েটই নয়, এটি নেটিভ জাভাস্ক্রিপ্ট API-এর উপর তৈরি করা হয়েছে, যার অর্থ হল আমরা কোডের একটি লিন বান্ডেল ডেলিভার করতে পারি যা ব্রাউজারে আগে থেকেই থাকা ফিচারের সুবিধা নেয়।
import {html, css, LitElement} from 'lit';
export class SimpleGreeting extends LitElement {
static styles = css`:host { color: blue; font-family: sans-serif; }`;
static properties = {
name: {type: String},
};
constructor() {
super();
this.name = 'there';
}
render() {
return html`Hey
${this.name}, welcome to Web Components!`;
}
}
customElements.define('simple-greeting', SimpleGreeting);
তবে, ওয়েব কম্পোনেন্টের সবচেয়ে আকর্ষণীয় দিক হল, এটি প্রায় যেকোনও বর্তমান জাভাস্ক্রিপ্ট ফ্রেমওয়ার্কের সাথে কাজ করে, এমনকি কোনও ফ্রেমওয়ার্ক না থাকলেও কাজ করে। পৃষ্ঠায় মূল জাভাস্ক্রিপ্ট প্যাকেজ রেফারেন্স করা হয়ে গেলে, ওয়েব কম্পোনেন্ট ব্যবহার করা নেটিভ HTML এলিমেন্ট ব্যবহার করার মতোই। এটি যে নেটিভ HTML এলিমেন্ট নয় তা বোঝার একমাত্র উপায় হল ট্যাগের মধ্যে থাকা হাইফেন, যা ব্রাউজারকে বোঝায় যে এটি একটি ওয়েব কম্পোনেন্ট।
শ্যাডো DOM স্টাইল এনক্যাপসুলেশন
নেটিভ HTML এলিমেন্টের যেমন Shadow DOM থাকে, ঠিক তেমনই ওয়েব কম্পোনেন্টেরও থাকে। শ্যাডো DOM হল কোনও এলিমেন্টের মধ্যে নোডের একটি লুকানো ট্রি। এটি দেখার সবচেয়ে ভালো উপায় হল, আপনার ওয়েব ইন্সপেক্টর খুলে "শ্যাডো DOM ট্রি দেখুন" বিকল্প চালু করা। এটি করার পরে, ইন্সপেক্টরে নেটিভ ইনপুট এলিমেন্ট দেখার চেষ্টা করুন—এখন আপনি সেই ইনপুট খুলে তার মধ্যে থাকা সব এলিমেন্ট দেখার বিকল্প পাবেন। আপনি আমাদের ওয়েব কম্পোনেন্টের একটির সাথেও এটি করে দেখতে পারেন—এর শ্যাডো DOM দেখতে আমাদের কাস্টম ইনপুট কম্পোনেন্ট পরীক্ষা করে দেখুন।
Shadow DOM-এর একটি সুবিধা (বা অসুবিধা, আপনার দৃষ্টিভঙ্গির উপর নির্ভর করে) হল স্টাইল এনক্যাপসুলেশন। আপনি যদি নিজের ওয়েব কম্পোনেন্টের মধ্যে CSS লেখেন, তাহলে সেই স্টাইলগুলি লিক হয়ে মূল পৃষ্ঠা বা অন্যান্য এলিমেন্টকে প্রভাবিত করতে পারে না; সেগুলি সম্পূর্ণভাবে কম্পোনেন্টের মধ্যেই থাকে। এছাড়াও, মূল পৃষ্ঠা বা পেরেন্ট ওয়েব কম্পোনেন্টের জন্য লেখা CSS আপনার ওয়েব কম্পোনেন্টে লিক হতে পারে না।
স্টাইলের এই এনক্যাপসুলেশন আমাদের কম্পোনেন্ট লাইব্রেরিতে একটি সুবিধা। এটি আমাদের আরও বেশি গ্যারান্টি দেয় যে কেউ আমাদের কোনও কম্পোনেন্ট ব্যবহার করলে, মূল পৃষ্ঠায় যে স্টাইলই প্রয়োগ করা হোক না কেন, সেটি আমাদের ইচ্ছা অনুযায়ীই দেখাবে। এবং আরও নিশ্চিত করতে, আমরা আমাদের সমস্ত ওয়েব কম্পোনেন্টের রুট বা "হোস্ট"-এ all: unset; যোগ করি।
:host {
all: unset;
display: block;
box-sizing: border-box;
text-align: start;
/* ... */
}
তবে, আপনার ওয়েব কম্পোনেন্ট ব্যবহারকারী কোনও ব্যক্তির যদি নির্দিষ্ট স্টাইল পরিবর্তন করার বৈধ কারণ থাকে, তাহলে কী হবে? এমন হতে পারে যে কোনও টেক্সটের লাইনে আরও বেশি কন্ট্রাস্ট প্রয়োজন অথবা কোনও বর্ডার আরও মোটা করতে হবে? আপনার কম্পোনেন্টে কোনও স্টাইল না থাকলে, আপনি কীভাবে সেই স্টাইলিং বিকল্পগুলি আনলক করতে পারেন?
এখানেই CSS কাস্টম প্রপার্টি কাজে লাগে।
CSS কাস্টম প্রপার্টি
কাস্টম প্রপার্টির নাম খুব যথাযথভাবে দেওয়া হয়েছে—এগুলি হল CSS প্রপার্টি যেগুলির নাম আপনি সম্পূর্ণভাবে নিজের মতো করে দিতে পারেন এবং প্রয়োজন অনুযায়ী যেকোনও ভ্যালু প্রয়োগ করতে পারেন। একমাত্র প্রয়োজনীয়তা হল, আপনাকে সেগুলির আগে দুটি হাইফেন যোগ করতে হবে। আপনার কাস্টম প্রপার্টি ঘোষণা করার পরে, var() ফাংশন ব্যবহার করে আপনার CSS-এ ভ্যালু ব্যবহার করা যেতে পারে।
:root {
--n-color-accent: rgb(53, 89, 199);
/* ... */
}
.n-color-accent-text {
color: var(--n-color-accent);
}
ইনহেরিটেন্সের ক্ষেত্রে, সব কাস্টম প্রপার্টি ইনহেরিট করা হয়, যা সাধারণ CSS প্রপার্টি ও ভ্যালুর সাধারণ আচরণ অনুসরণ করে। মূল এলিমেন্ট বা এলিমেন্টে প্রয়োগ করা যেকোনও কাস্টম প্রপার্টি, অন্যান্য প্রপার্টির ভ্যালু হিসেবে ব্যবহার করা যেতে পারে। আমাদের CSS ফ্রেমওয়ার্ক ব্যবহার করে রুট এলিমেন্টে প্রয়োগ করার মাধ্যমে আমরা ডিজাইন টোকেনের জন্য কাস্টম প্রপার্টি ব্যাপকভাবে ব্যবহার করি, যার অর্থ হল পৃষ্ঠার সব এলিমেন্ট এইসব টোকেন ভ্যালু ব্যবহার করতে পারে, তা কোনও ওয়েব কম্পোনেন্ট, CSS হেল্পার ক্লাস বা কোনও ডেভেলপার আমাদের টোকেনের তালিকা থেকে কোনও ভ্যালু নিতে চাইলে, যাই হোক না কেন।
var() ফাংশন ব্যবহার করে কাস্টম প্রপার্টি ইনহেরিট করার এই ক্ষমতা হল এমন একটি পদ্ধতি যার মাধ্যমে আমরা আমাদের ওয়েব কম্পোনেন্টের শ্যাডো DOM-এর মাধ্যমে কাজ করি এবং ডেভেলপারদের আমাদের কম্পোনেন্ট স্টাইল করার সময় আরও সূক্ষ্ম নিয়ন্ত্রণ প্রদান করি।
Nord ওয়েব কম্পোনেন্টে কাস্টম প্রপার্টি
আমাদের ডিজাইন সিস্টেমের জন্য কোনও কম্পোনেন্ট ডেভেলপ করার সময়, আমরা এর CSS-এর ব্যাপারে চিন্তাভাবনা করে সিদ্ধান্ত নিই—আমরা এমন কোড তৈরি করতে চাই যা খুব বেশি জটিল নয় এবং সহজেই ম্যানেজ করা যায়। আমাদের কাছে থাকা ডিজাইন টোকেনগুলি রুট এলিমেন্টে আমাদের প্রধান CSS ফ্রেমওয়ার্কের মধ্যে কাস্টম প্রপার্টি হিসাবে সংজ্ঞায়িত করা হয়েছে।
:root {
--n-space-m: 16px;
--n-space-l: 24px;
/* ... */
--n-color-background: rgb(255, 255, 255);
--n-color-border: rgb(216, 222, 228);
/* ... */
}
এই টোকেন ভ্যালুগুলি আমাদের কম্পোনেন্টের মধ্যে রেফারেন্স হিসেবে ব্যবহার করা হয়। কিছু ক্ষেত্রে, আমরা সরাসরি CSS প্রপার্টিতে ভ্যালু প্রয়োগ করব, তবে অন্যান্য ক্ষেত্রে, আমরা আসলে একটি নতুন প্রাসঙ্গিক কাস্টম প্রপার্টি সংজ্ঞায়িত করব এবং সেটিতে ভ্যালু প্রয়োগ করব।
:host {
--n-tab-group-padding: 0;
--n-tab-list-background: var(--n-color-background);
--n-tab-list-border: inset 0 -1px 0 0 var(--n-color-border);
/* ... */
}
.n-tab-group-list {
box-shadow: var(--n-tab-list-border);
background-color: var(--n-tab-list-background);
gap: var(--n-space-s);
/* ... */
}
এছাড়াও, আমরা কিছু ভ্যালু অ্যাবস্ট্র্যাক্ট করব যা কম্পোনেন্টের জন্য নির্দিষ্ট কিন্তু আমাদের টোকেনে নেই এবং সেগুলিকে একটি প্রাসঙ্গিক কাস্টম প্রপার্টিতে পরিণত করব। কম্পোনেন্টের সাথে প্রাসঙ্গিক কাস্টম প্রপার্টি আমাদের দুটি মূল সুবিধা প্রদান করে। প্রথমত, এর অর্থ হল আমরা আমাদের CSS-এর সাথে আরও "ড্রাই" হতে পারি কারণ সেই মানটি কম্পোনেন্টের ভিতরে একাধিক প্রপার্টিতে প্রয়োগ করা যেতে পারে।
.n-tab-group-list::before {
/* ... */
padding-inline-start: var(--n-tab-group-padding);
}
.n-tab-group-list::after {
/* ... */
padding-inline-end: var(--n-tab-group-padding);
}
আর দ্বিতীয়ত, এটি কম্পোনেন্ট স্টেট ও ভেরিয়েশন পরিবর্তনকে খুব পরিষ্কার করে তোলে—ধরুন, আপনি হোভার বা অ্যাক্টিভ স্টেট অথবা এই ক্ষেত্রে ভেরিয়েশন স্টাইল করছেন, তখন এইসব প্রপার্টি আপডেট করার জন্য শুধু কাস্টম প্রপার্টি পরিবর্তন করলেই হয়।
:host([padding="l"]) {
--n-tab-group-padding: var(--n-space-l);
}
তবে সবচেয়ে শক্তিশালী সুবিধা হল, কোনও কম্পোনেন্টে আমরা যখন এইসব প্রাসঙ্গিক কাস্টম প্রপার্টি সংজ্ঞায়িত করি, তখন আমাদের প্রতিটি কম্পোনেন্টের জন্য এক ধরনের কাস্টম CSS API তৈরি করি, যা সেই কম্পোনেন্টের ব্যবহারকারী ট্যাপ করতে পারেন।
<nord-tab-group label="Title">
<!-- ... -->
</nord-tab-group>
<style>
nord-tab-group {
--n-tab-group-padding: var(--n-space-xl);
}
</style>
আগের উদাহরণে আমাদের একটি ওয়েব কম্পোনেন্ট দেখানো হয়েছে যেখানে সিলেক্টর ব্যবহার করে প্রাসঙ্গিক কাস্টম প্রপার্টি পরিবর্তন করা হয়েছে। এই সম্পূর্ণ পদ্ধতির ফলাফল হল এমন একটি কম্পোনেন্ট যা ব্যবহারকারীকে যথেষ্ট স্টাইলিং নমনীয়তা প্রদান করে এবং একই সাথে বেশিরভাগ আসল স্টাইল চেক করে। এছাড়াও, বোনাস হিসেবে, কম্পোনেন্ট ডেভেলপার হিসেবে আমাদের কাছে ব্যবহারকারীর প্রয়োগ করা সেইসব স্টাইল ইন্টারসেপ্ট করার ক্ষমতা আছে। আমরা যদি সেইসব প্রপার্টির কোনও একটি অ্যাডজাস্ট বা এক্সটেন্ড করতে চাই, তাহলে ব্যবহারকারীকে তার কোনও কোড পরিবর্তন না করেই আমরা তা করতে পারি।
আমরা এই পদ্ধতিকে অত্যন্ত শক্তিশালী বলে মনে করি, শুধু আমাদের ডিজাইন সিস্টেম কম্পোনেন্টের ক্রিয়েটর হিসেবেই নয়, আমাদের ডেভেলপমেন্ট টিমের জন্যও যখন তারা আমাদের প্রোডাক্টে এই কম্পোনেন্টগুলি ব্যবহার করে।
কাস্টম প্রপার্টি আরও উন্নত করা হচ্ছে
এই নিবন্ধটি লেখার সময় আমরা আমাদের ডকুমেন্টেশনে এই প্রাসঙ্গিক কাস্টম প্রপার্টিগুলি প্রকাশ করিনি; তবে, আমরা এটি করার পরিকল্পনা করছি যাতে আমাদের বৃহত্তর ডেভেলপমেন্ট টিম এই প্রপার্টিগুলি বুঝতে এবং ব্যবহার করতে পারে। আমাদের কম্পোনেন্ট npm-এ একটি ম্যানিফেস্ট ফাইলের সাথে প্যাকেজ করা হয়, যার মধ্যে সেগুলি সম্পর্কে জানার জন্য সবকিছু থাকে। আমাদের ডকুমেন্টেশন সাইট ডেপ্লয় করার সময় আমরা ম্যানিফেস্ট ফাইল ডেটা হিসেবে ব্যবহার করি, যা Eleventy এবং এর গ্লোবাল ডেটা ফিচার ব্যবহার করে করা হয়। আমরা এই ম্যানিফেস্ট ডেটা ফাইলে এইসব প্রাসঙ্গিক কাস্টম প্রপার্টি অন্তর্ভুক্ত করার পরিকল্পনা করেছি।
আমরা আরও একটি ক্ষেত্র উন্নত করতে চাই, সেটি হল কীভাবে এইসব প্রাসঙ্গিক কাস্টম প্রপার্টি ভ্যালু ইনহেরিট করে। এখন, উদাহরণস্বরূপ, আপনি যদি দুটি ডিভাইডার কম্পোনেন্টের রঙ অ্যাডজাস্ট করতে চান, তাহলে আপনাকে সিলেক্টরের মাধ্যমে নির্দিষ্টভাবে সেই দুটি কম্পোনেন্টকে টার্গেট করতে হবে অথবা স্টাইল অ্যাট্রিবিউট সহ এলিমেন্টে সরাসরি কাস্টম প্রপার্টি প্রয়োগ করতে হবে। এটি ঠিক বলে মনে হতে পারে, তবে ডেভেলপার যদি কোনও কন্টেনিং এলিমেন্ট বা এমনকি রুট লেভেলে সেইসব স্টাইল সংজ্ঞায়িত করতে পারেন, তাহলে এটি আরও সহায়ক হবে।
<nord-divider></nord-divider>
<section>
<nord-divider></nord-divider>
<!-- ... -->
</section>
<style>
nord-divider {
--n-divider-color: var(--n-color-status-danger);
}
section {
padding: var(--n-space-s);
background: var(--n-color-surface-raised);
}
section nord-divider {
--n-divider-color: var(--n-color-status-success);
}
</style>
আপনাকে কম্পোনেন্টে সরাসরি কাস্টম প্রপার্টি ভ্যালু সেট করতে হবে কারণ আমরা কম্পোনেন্ট হোস্ট সিলেক্টর ব্যবহার করে একই এলিমেন্টে সেগুলি সংজ্ঞায়িত করছি। আমরা কম্পোনেন্টে সরাসরি যে গ্লোবাল ডিজাইন টোকেন ব্যবহার করি তা এই সমস্যার দ্বারা প্রভাবিত না হয়ে সরাসরি পাস হয়ে যায় এবং এমনকি পেরেন্ট এলিমেন্টে ইন্টারসেপ্ট করা যেতে পারে। আমরা কীভাবে দুটিরই সেরা সুবিধা পেতে পারি?
ব্যক্তিগত ও সর্বজনীন কাস্টম প্রপার্টি
ব্যক্তিগত কাস্টম প্রপার্টি হল এমন কিছু যা Lea Verou দ্বারা একত্রিত করা হয়েছে, যা কম্পোনেন্টে একটি প্রাসঙ্গিক "ব্যক্তিগত" কাস্টম প্রপার্টি কিন্তু ফলব্যাক সহ একটি "পাবলিক" কাস্টম প্রপার্টিতে সেট করা হয়েছে।
:host {
--_n-divider-color: var(--n-divider-color, var(--n-color-border));
--_n-divider-size: var(--n-divider-size, 1px);
}
.n-divider {
border-block-start: solid var(--_n-divider-size) var(--_n-divider-color);
/* ... */
}
এইভাবে আমাদের প্রাসঙ্গিক কাস্টম প্রপার্টি সংজ্ঞায়িত করার অর্থ হল, আমরা এখনও আগে যা করছিলাম তা করতে পারি, যেমন গ্লোবাল টোকেন ভ্যালু ইনহেরিট করা এবং আমাদের কম্পোনেন্ট কোড জুড়ে ভ্যালু আবার ব্যবহার করা; তবে কম্পোনেন্টটি নিজের বা যেকোনও পেরেন্ট এলিমেন্টের উপর সেই প্রপার্টির নতুন সংজ্ঞা ইনহেরিট করবে।
<nord-divider></nord-divider>
<section>
<nord-divider></nord-divider>
<!-- ... -->
</section>
<style>
nord-divider {
--n-divider-color: var(--n-color-status-danger);
}
section {
padding: var(--n-space-s);
background: var(--n-color-surface-raised);
--n-divider-color: var(--n-color-status-success);
}
</style>
যদিও এই পদ্ধতিটি সত্যিই "ব্যক্তিগত" নয় বলে যুক্তি দেওয়া যেতে পারে, তবুও আমরা মনে করি যে এটি একটি সমস্যার একটি সুন্দর সমাধান যা নিয়ে আমরা চিন্তিত ছিলাম। সুযোগ পেলে, আমরা আমাদের কম্পোনেন্টে এই সমস্যার সমাধান করব যাতে আমাদের ডেভেলপমেন্ট টিম কম্পোনেন্টের ব্যবহারের উপর আরও বেশি নিয়ন্ত্রণ পায় এবং একই সাথে আমাদের কাছে থাকা সুরক্ষা ব্যবস্থার সুবিধা নিতে পারে।
CSS কাস্টম প্রপার্টির সাথে আমরা কীভাবে ওয়েব কম্পোনেন্ট ব্যবহার করি সেই বিষয়ে এই ইনসাইট আপনার কাজে লাগবে বলে আশা করি। আপনার মতামত আমাদের জানান এবং আপনি যদি নিজের কাজে এইসব পদ্ধতির কোনও একটি ব্যবহার করার সিদ্ধান্ত নেন, তাহলে আমাকে Twitter-এ @DavidDarnes-এ খুঁজে পাবেন। এছাড়াও, আপনি Twitter-এ Nordhealth @NordhealthHQ এবং আমার টিমের বাকি সদস্যদের খুঁজে পাবেন, যারা এই ডিজাইন সিস্টেমটি একসাথে আনতে এবং এই ডকুমেন্টে উল্লেখ করা ফিচারগুলি কার্যকর করার জন্য কঠোর পরিশ্রম করেছেন: @Viljamis, @WickyNilliams এবং @eric_habich।