আগের পর্বে React Router শিখেছিলাম। এই পর্বে আমরা দেখব React-এ Styling-এর বিভিন্ন উপায় — এতদিন আমরা শুধু inline style অবজেক্ট ব্যবহার করেছি (পর্ব ২-এ শেখা), এবার CSS Modules আর conditional className-সহ পুরো চিত্রটা দেখব।
React-এ স্টাইলিংয়ের চারটা মূল উপায়
| পদ্ধতি | সংক্ষেপে |
|---|---|
| সাধারণ CSS ফাইল | Advanced CSS সিরিজের মতোই, সব ক্লাস গ্লোবাল |
| Inline Style | JavaScript অবজেক্ট, ডাইনামিক মানের জন্য উপযুক্ত |
| CSS Modules | প্রতিটা কম্পোনেন্টের CSS স্বয়ংক্রিয়ভাবে "স্কোপড", ক্লাস নাম সংঘর্ষ হয় না |
| CSS-in-JS লাইব্রেরি | styled-components ইত্যাদি — এই সিরিজের বাইরে |
পদ্ধতি ১ — সাধারণ CSS ফাইল
একটা সাধারণ .css ফাইল বানিয়ে সরাসরি import করা যায় — Advanced CSS সিরিজে শেখা সবকিছুই এখানে কাজ করে (BEM, Custom Properties, সবকিছু)।
/* Card.css */
.card {
background: white;
border-radius: 8px;
padding: 16px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.card__title {
font-size: 18px;
font-weight: bold;
}
// Card.jsx
import "./Card.css";
function Card({ title }) {
return (
<div className="card">
<h3 className="card__title">{title}</h3>
</div>
);
}
সমস্যা: এই CSS গ্লোবাল — যদি আরেকটা component-এও .card ক্লাস ব্যবহার করে, দুটোর স্টাইল একে অপরের সাথে সংঘর্ষ করতে পারে। Advanced CSS পর্ব ২-এ শেখা BEM এই সমস্যা কমায়, কিন্তু পুরোপুরি সমাধান করে না।
পদ্ধতি ২ — CSS Modules (সংঘর্ষ-মুক্ত)
.module.css এক্সটেনশন দিয়ে ফাইল বানালে Vite স্বয়ংক্রিয়ভাবে প্রতিটা ক্লাস নামকে "ইউনিক" বানিয়ে দেয় — এতে গ্লোবাল সংঘর্ষের ভয় থাকে না।
/* Card.module.css */
.card {
background: white;
border-radius: 8px;
padding: 16px;
}
.title {
font-size: 18px;
font-weight: bold;
}
// Card.jsx
import styles from "./Card.module.css"; // একটা অবজেক্ট হিসেবে ইমপোর্ট হয়
function Card({ title }) {
return (
<div className={styles.card}>
<h3 className={styles.title}>{title}</h3>
</div>
);
}
ব্রাউজারে গিয়ে দেখলে styles.card-এর আসল মান দেখাবে কিছুটা এরকম — "Card_card__a1B2c" — Vite স্বয়ংক্রিয়ভাবে ফাইলের নাম আর একটা র্যান্ডম হ্যাশ জুড়ে দেয়, যাতে অন্য কোনো .card ক্লাসের সাথে কখনো সংঘর্ষ না হয়।
পদ্ধতি ৩ — Inline Style রিক্যাপ
পর্ব ২-এ শেখা inline style এখনো প্রাসঙ্গিক — বিশেষ করে যখন স্টাইলের মান সম্পূর্ণ ডাইনামিক (JavaScript ভ্যারিয়েবল থেকে সরাসরি আসছে, যেমন প্রোগ্রেস বার-এর প্রস্থ)।
function ProgressBar({ percent }) {
return (
<div style={{ width: "100%", background: "#e5e7eb", borderRadius: "999px" }}>
<div style={{ width: `${percent}%`, background: "#2563eb", height: "8px", borderRadius: "999px" }} />
</div>
);
}
এখানে width: `${percent}%` সরাসরি JavaScript থেকে গণনা করা — এটা CSS ফাইলে সহজে করা যেত না, কারণ percent রানটাইমে পাল্টায়।
কখন কোন পদ্ধতি — একনজরে
| পরিস্থিতি | সুপারিশ |
|---|---|
| স্থির, পুনর্ব্যবহারযোগ্য স্টাইল | CSS Modules |
| গ্লোবাল বেস স্টাইল (reset, টাইপোগ্রাফি) | সাধারণ CSS ফাইল |
| সম্পূর্ণ ডাইনামিক মান (JS থেকে গণনা করা) | Inline Style |
Conditional className — শর্তসাপেক্ষ ক্লাস
পর্ব ৭-এর Conditional Rendering প্রায়ই ক্লাস নামেও প্রয়োগ হয় — একটা state অনুযায়ী ভিন্ন ক্লাস বসানো।
function Button({ isActive }) {
return (
<button className={isActive ? "btn btn--active" : "btn"}>
চাপো
</button>
);
}
একাধিক শর্তসাপেক্ষ ক্লাস একসাথে জুড়তে হলে template literal সবচেয়ে সহজ পদ্ধতি — Advanced JS-এ শেখা template literal সিনট্যাক্স:
function Button({ isActive, isDisabled }) {
return (
<button
className={`btn ${isActive ? "btn--active" : ""} ${isDisabled ? "btn--disabled" : ""}`}
>
চাপো
</button>
);
}
সতর্কতা: খালি স্ট্রিং থাকলে ক্লাস নামে অতিরিক্ত স্পেস থাকবে — সাধারণত এতে সমস্যা হয় না, কিন্তু বড় প্রজেক্টে clsx বা classnames-এর মতো ছোট লাইব্রেরি এই কাজটা আরও পরিষ্কারভাবে করতে সাহায্য করে (এই সিরিজে আমরা vanilla পদ্ধতিতেই থাকব)।
লাইভ ডেমো — Conditional Style ও className
নিচের ট্যাব বাটনে চাপো — সিলেক্টেড ট্যাবের স্টাইল ডাইনামিকভাবে পাল্টাচ্ছে, inline style আর conditional logic মিলিয়ে।
একটা সম্পূর্ণ উদাহরণ — CSS Modules দিয়ে কার্ড কম্পোনেন্ট
চলো একটা সম্পূর্ণ উদাহরণ দেখি — CSS Modules, conditional className, আর props মিলিয়ে একটা বই কার্ড।
/* BookCard.module.css */
.card {
background: white;
border-radius: 8px;
padding: 16px;
border: 2px solid transparent;
transition: border-color 0.3s;
}
.card.featured {
border-color: #facc15;
}
.title {
font-size: 16px;
font-weight: bold;
margin: 0 0 4px 0;
}
.available {
color: #16a34a;
}
.unavailable {
color: #9ca3af;
}
// BookCard.jsx
import styles from "./BookCard.module.css";
function BookCard({ title, isAvailable, isFeatured }) {
return (
<div className={`${styles.card} ${isFeatured ? styles.featured : ""}`}>
<h3 className={styles.title}>{title}</h3>
<p className={isAvailable ? styles.available : styles.unavailable}>
{isAvailable ? "পাওয়া যাচ্ছে" : "স্টক নেই"}
</p>
</div>
);
}
export default BookCard;
এখানে CSS Modules-এর ক্লাস নাম (styles.card, styles.featured) template literal দিয়ে conditional-ভাবে জোড়া লাগানো হয়েছে — এটাই এই পর্বের প্রায় সব কনসেপ্টের মিশ্রণ।
নিজে চেষ্টা করো
Exercise:
- একটা
Badge.module.cssবানাও, কয়েকটা রঙের ভ্যারিয়েন্ট (success, danger, warning) সহ। - উপরের
BookCardনিজে বানাও, নিজের প্রজেক্টে বসিয়ে টেস্ট করো। - একটা প্রোগ্রেস বার বানাও যেখানে প্রস্থ সম্পূর্ণ ডাইনামিক (inline style দিয়ে), আর রঙ conditional className দিয়ে (৫০%-এর নিচে লাল, উপরে সবুজ)।
- একই ক্লাস নাম (যেমন
.title) দুটো ভিন্ন.module.cssফাইলে ব্যবহার করে দেখো — সংঘর্ষ হয় কিনা যাচাই করো (হওয়া উচিত না)।
পরের পর্বে যা থাকছে
এতে শেষ হলো "Routing ও Styling" অংশ। পরের পর্বে আমরা শিখব useRef ও Custom Hook — DOM এলিমেন্টের সরাসরি রেফারেন্স নেওয়া, আর নিজের প্রথম Custom Hook বানানোর বেসিক।