সরাসরি পর্বে যান
পর্ব ২২ · ৫৯-এর মধ্যে · মডিউল ৩

ব্যাকগ্রাউন্ড, gradient, বর্ডার আর ছায়া

CSS Backgrounds, Gradients, Borders & Shadows — cover vs contain, Layers, Conic Pie Charts, border-radius, box-shadow & drop-shadow

Taught in Bangla, this lesson covers CSS backgrounds: background images with repeat, position, size and attachment, cover versus contain, origin and clip including gradient text, the background shorthand and layered backgrounds, linear, radial, conic and repeating gradients such as pie charts, borders, border-radius, border-image and outline, box-shadow, text-shadow and drop-shadow, plus performance and accessibility costs.

এই পর্বে যা শিখবেন

  • background-এর প্রতিটি অংশ — color, image, repeat, position, size, attachment, origin, clip — কী করে আর কেন
  • shorthand আর একাধিক স্তর দিয়ে ছবির ওপর পড়ার মতো লেখা বসানো
  • linear, radial, conic আর repeating gradient — color stop, কোণ, ডোরা আর পাই চার্ট
  • বর্ডার, গোল কোণ, border-image আর outline-এর পার্থক্য
  • box-shadow, text-shadow আর drop-shadow — বাস্তব ছায়া, পারফরম্যান্স আর অ্যাক্সেসিবিলিটির সাবধানতা

১ · বাক্সের পেছনের দেয়াল — background কী

পর্ব ১৯-এর box model-এ দেখেছেন, পাতার প্রতিটি element আসলে একটি আয়তাকার বাক্স — ভেতরে content, তার চারপাশে padding, তারপর border, সবার বাইরে margin. এই পর্বে আমরা সেই বাক্সকে সাজাব। প্রশ্ন তিনটি: বাক্সের পেছনে কী থাকবে, তার কিনারা দেখতে কেমন হবে, আর বাক্সটি পাতা থেকে কতটা উঁচু মনে হবে।

একটি নতুন দোকানঘরের কথা ভাবুন। প্রথমে দেয়ালে এক পোঁচ রং — এটা background-color. তারপর দেয়ালে ওয়ালপেপার বা পোস্টার সাঁটা — এটা background-image. দেয়ালের চারপাশে কাঠের ফ্রেম — border. আর সাইনবোর্ডটি দেয়াল থেকে একটু সামনে ঝুলিয়ে দিলে পেছনে যে ছায়া পড়ে, সেটাই box-shadow. দোকানের মাল (লেখা, ছবি) এসব সাজের ওপরে বসে — সাজ বদলালে মাল বদলায় না।

সবচেয়ে সহজ জিনিস দিয়ে শুরু করি: background-color. পর্ব ২০-এর যেকোনো রঙের লেখা এখানে চলে — #006a4e, rgb(0 106 78), oklch(45% 0.1 160). ডিফল্ট মান transparent, অর্থাৎ স্বচ্ছ — তাই কিছু না লিখলে নিচের element-এর রং দেখা যায়। background কোনো inheritance-এর মাধ্যমে আসে না; ভেতরের element-কে “রঙিন” দেখায় কারণ সে নিজে স্বচ্ছ, আর তার পেছনে বাইরের (parent) element-এর রং দেখা যাচ্ছে।

ব্যাকগ্রাউন্ড কতদূর পর্যন্ত আঁকা হয়? ডিফল্টে border-এর বাইরের কিনারা পর্যন্ত — content, padding, এমনকি border-এর নিচেও। ড্যাশ দেওয়া বা আধা-স্বচ্ছ border দিলে নিচে রংটা উঁকি দেয়, তখন এটা চোখে পড়ে। margin-এর জায়গায় কখনো ব্যাকগ্রাউন্ড আঁকা হয় না — margin বাক্সের বাইরের ফাঁকা জায়গা।

মূল ধারণা

একটি element-এর ব্যাকগ্রাউন্ড আসলে কয়েকটি স্তর (layer): সবার নিচে একটিমাত্র রং, তার ওপরে শূন্য বা একাধিক “ছবি” — আসল ছবির ফাইল হোক বা ব্রাউজারের আঁকা gradient. প্রতিটি স্তরের নিজস্ব repeat, position, size থাকতে পারে। এই একটি ধারণা মাথায় রাখলে বাকি সব property সহজে মেলে।

রং বেছে নেওয়ার আগে পড়ার কথা ভাবুন। লেখা আর ব্যাকগ্রাউন্ডের মধ্যে যথেষ্ট contrast লাগবে — WCAG 2.2 সাধারণ লেখার জন্য অন্তত 4.5:1 অনুপাত চায়। হালকা ধূসর ব্যাকগ্রাউন্ডে হালকা ধূসর লেখা দেখতে “মিনিমাল”, কিন্তু রোদে ফোন হাতে রিকশায় বসা মানুষ বা কম দৃষ্টিশক্তির পাঠকের জন্য অপাঠ্য।

২ · ছবি দিয়ে ব্যাকগ্রাউন্ড — repeat, position, size আর attachment

background-image: url("photo.jpg") লিখলে ছবিটি বাক্সের পেছনে বসে। কিন্তু বাক্স আর ছবির মাপ প্রায় কখনো মেলে না। তখন ব্রাউজারকে চারটি প্রশ্নের উত্তর দিতে হয়, আর প্রতিটির জন্য আলাদা property আছে:

প্রশ্নPropertyপ্রচলিত মান
ছবি ছোট হলে বারবার বসবে?background-repeatrepeat (ডিফল্ট), no-repeat, repeat-x, repeat-y, space, round
বাক্সের কোথায় বসবে?background-positioncenter, top right, 20% 80%, right 16px bottom 8px
কত বড় হবে?background-sizeauto, cover, contain, 200px auto, 50%
স্ক্রল করলে সাথে সরবে?background-attachmentscroll (ডিফল্ট), fixed, local

সবচেয়ে বেশি ব্যবহার হয় background-size-এর দুটি শব্দ, আর সবচেয়ে বেশি গোলমালও এখানেই। cover মানে “ছবির অনুপাত ঠিক রেখে এতটা বড় করা, যাতে পুরো বাক্স ঢাকা পড়ে” — বাক্স আর ছবির অনুপাত না মিললে ছবির কিছু অংশ বাইরে চলে যায়। contain মানে “অনুপাত ঠিক রেখে এতটা বড় করা, যাতে পুরো ছবি বাক্সের ভেতরে আঁটে” — তখন কোনো এক দিকে ফাঁকা থাকে। দুটোতেই ছবি কখনো চ্যাপ্টা বা লম্বাটে হয় না।

বাঁধাইয়ের দোকানে একটি চওড়া ছবি বর্গাকার ফ্রেমে বাঁধাতে দিলেন। কারিগর দুইভাবে করতে পারেন। এক — ছবি বড় করে পুরো ফ্রেম ভরিয়ে দেবেন, দুই পাশের কিছু অংশ ফ্রেমের পেছনে ঢুকে যাবে (cover). দুই — পুরো ছবিটাই দেখাবেন, ওপর-নিচে সাদা মাউন্ট বোর্ড থাকবে (contain). কোনোটাই ভুল নয়; প্রশ্ন হলো আপনার কাছে কোনটা জরুরি — ফ্রেম ভরা, না পুরো ছবি।

নিচের তিনটি বাক্সে একই ছবি — এই সাইটের একটি কভার ছবি, যার অনুপাত প্রায় ১৯:১০। CSS বদলে দেখুন কী হয়:

.box {
  height: 140px;
  margin-bottom: 12px;
  border: 2px solid #334;
  background-color: #e8f0fe;
  background-image: url("../image/computer-fundamentals-cover.jpg");
}
.box span {
  background: white;
  font: bold 14px sans-serif;
  padding: 2px 6px;
}
.cover   { background-size: cover; background-position: center; }
.contain { background-size: contain; background-repeat: no-repeat;
           background-position: center; }
.tile    { background-size: 80px auto; }

প্রথম বাক্সে ছবি পুরো জায়গা ঢেকেছে, কিন্তু ওপর-নিচের অংশ কাটা পড়েছে। দ্বিতীয়টিতে পুরো ছবি দেখা যাচ্ছে, দুই পাশে হালকা নীল background-color উঁকি দিচ্ছে — রংটাই ফাঁকা জায়গা ভরছে। তৃতীয়টিতে ছবি ৮০ পিক্সেল চওড়া হয়ে টালির মতো বারবার বসেছে, কারণ repeat ডিফল্ট। চেষ্টা করুন: .cover-এ center-কে top করুন — ছবির কোন অংশ দেখা যায়? তারপর .tile-এ background-repeat: round; যোগ করুন — ব্রাউজার টালির মাপ সামান্য বদলে দেয় যাতে কিনারায় আধা-কাটা টালি না থাকে।

position-এর হিসাব, আর attachment-এর তিন রূপ

background-position: 20% 80%-এর মানে একটু মজার। এটা “বাঁ দিক থেকে ২০ শতাংশ দূরে” নয়; বরং ছবির ২০ শতাংশ বিন্দুটি বাক্সের ২০ শতাংশ বিন্দুর ওপর বসে। তাই 0% মানে ছবির বাঁ কিনারা বাক্সের বাঁ কিনারায়, 100% মানে ডান কিনারা ডান কিনারায়, আর 50% মানে ঠিক মাঝখানে — center-এর সমান। নির্দিষ্ট কোনো কোণা থেকে মাপতে চাইলে চার-শব্দের রূপ লিখুন: right 16px bottom 8px.

  • scroll (ডিফল্ট) — ব্যাকগ্রাউন্ড element-এর সাথে বাঁধা; পাতা স্ক্রল করলে element-এর সাথেই সরে।
  • fixed — ব্যাকগ্রাউন্ড ব্রাউজারের জানালার (viewport) সাথে বাঁধা; লেখা সরে, ছবি দাঁড়িয়ে থাকে। একসময় “parallax” চেহারার জন্য খুব জনপ্রিয় ছিল। কিন্তু অনেক মোবাইল ব্রাউজার, বিশেষত iPhone-এর Safari, এটি উপেক্ষা করে, আর ডেস্কটপেও প্রতিটি স্ক্রলে নতুন করে আঁকার খরচ বাড়ায়।
  • local — নিজস্ব স্ক্রলবার আছে এমন বাক্সের (overflow: auto) ভেতরের content-এর সাথে ব্যাকগ্রাউন্ড সরে। স্ক্রল-তালিকায় “আরও আছে” ছায়া দেখাতে কাজে লাগে।

ছবিটা কি সত্যিই ব্যাকগ্রাউন্ড? শুধু সাজসজ্জার ছবি (নকশা, টেক্সচার, আবছা ফটো) CSS-এ রাখুন। কিন্তু যে ছবি কোনো তথ্য দেয় — পণ্যের ছবি, মানুষের মুখ, চার্ট — সেটি HTML-এ <img alt="…"> দিয়ে রাখুন (পর্ব ০৬)। CSS ব্যাকগ্রাউন্ডের কোনো alt text নেই, screen reader সেটিকে দেখতেই পায় না, আর প্রিন্ট করার সময় অনেক ব্রাউজার ব্যাকগ্রাউন্ড ছাপেই না।

৩ · ছবি কোথা থেকে শুরু, কোথায় কাটা — origin, clip আর রঙিন লেখা

বাক্সের তিনটি সীমারেখা আছে: border-এর বাইরের কিনারা (border-box), padding-এর কিনারা (padding-box), আর content-এর কিনারা (content-box). ব্যাকগ্রাউন্ডের দুটি আলাদা প্রশ্নে এই তিনটি ব্যবহার হয়:

background-origin

ছবির অবস্থান আর মাপ কোন বাক্স ধরে হিসাব হবে। ডিফল্ট padding-box — তাই top left মানে padding-এর কোণা, border-এর নিচে নয়।

হিসাবের শুরু

background-clip

আঁকা ব্যাকগ্রাউন্ড কোথায় কেটে ফেলা হবে। ডিফল্ট border-box — border-এর নিচ পর্যন্ত আঁকা। padding-box দিলে border-এর নিচে কিছু থাকে না।

আঁকার সীমা

background-clip-এর একটি চতুর্থ মান আছে, যা সবচেয়ে জনপ্রিয়: text. এতে ব্যাকগ্রাউন্ড শুধু লেখার অক্ষরগুলোর আকারে কাটা হয়। লেখার নিজের রং স্বচ্ছ করে দিলে মনে হয় অক্ষরগুলোই gradient দিয়ে রং করা। অনেক বছর এটি শুধু -webkit- উপসর্গ দিয়ে চলত; এখন উপসর্গ ছাড়া রূপটি সব প্রধান ব্রাউজারে চলে (Baseline).

.demo {
  padding: 16px;
  margin-bottom: 10px;
  border: 10px dashed rgb(0 0 0 / .5);
  background: linear-gradient(90deg, #006a4e, #f4b400);
  font: 14px monospace;
}
.b1 { background-clip: border-box; }
.b2 { background-clip: padding-box; }
.b3 { background-clip: content-box; }

.title {
  font: 800 36px sans-serif;
  color: #b3122e;                  /* fallback */
}
@supports (background-clip: text) {
  .title {
    background: linear-gradient(90deg, #006a4e, #f42a41);
    background-clip: text;
    color: transparent;
  }
}

প্রথম বাক্সে gradient ড্যাশ-দেওয়া border-এর ফাঁক দিয়েও দেখা যাচ্ছে। দ্বিতীয়টিতে border-এর নিচটা সাদা — gradient শুধু padding পর্যন্ত। তৃতীয়টিতে padding-এর জায়গাও ফাঁকা, রং শুধু লেখার এলাকায়। নিচে শিরোনামের অক্ষরগুলো সবুজ থেকে লাল gradient-এ রাঙানো। চেষ্টা করুন: .b2-এ background-origin: border-box; যোগ করে দেখুন gradient-এর রঙের ক্রম একটু সরে যায় কি না। তারপর @supports অংশটি পুরো মুছে দিন — শিরোনাম সাধারণ লাল রঙে ফিরে আসবে, কারণ সেটাই fallback.

রঙিন লেখার অ্যাক্সেসিবিলিটি ফাঁদ। color: transparent দেওয়ার পর যদি কোনো কারণে ব্যাকগ্রাউন্ড না আঁকা হয় (পুরোনো ব্রাউজার, ছবি লোড না হওয়া, Windows-এর contrast থিম বা forced colors মোড), লেখাটা পুরো অদৃশ্য হয়ে যেতে পারে। তাই (১) সবসময় একটি সাধারণ color fallback রাখুন আর @supports দিয়ে মুড়ে দিন, (২) gradient-এর সবচেয়ে হালকা রঙের সাথেও contrast মাপুন, (৩) এটা শুধু বড় শিরোনামে ব্যবহার করুন — অনুচ্ছেদের লেখায় নয়। লেখা নির্বাচন করলে বা জুম করলেও একবার দেখে নিন।

৪ · shorthand আর একাধিক স্তর — ছবির ওপর পড়ার মতো লেখা

আটটি আলাদা property লেখা ক্লান্তিকর। তাই আছে shorthand — একটি background লিখেই সব বলা যায়:

/* image  position / size  repeat  attachment  origin clip  color */
.hero {
  background: url("dhaka.jpg") center / cover no-repeat #1b2a4a;
}

দুটি নিয়ম মনে রাখুন। এক: position আর size-এর মাঝে স্ল্যাশ / লাগে, আর size কখনো position ছাড়া একা বসে না — center / cover ঠিক, শুধু cover লিখলে পুরো লাইনটাই বাতিল। দুই: shorthand যে অংশ লেখেননি সেটিকে ডিফল্টে ফিরিয়ে দেয়। আগে background-color: red লিখে পরে background: url(a.png) লিখলে লাল রং মুছে যায় — নতুনদের সবচেয়ে প্রচলিত বিভ্রান্তি এটাই (কেন পরেরটা জেতে, তা পর্ব ১৮-এর cascade-এর হিসাব)।

এবার আসল শক্তি: কমা দিয়ে একাধিক স্তর। প্রতিটি স্তরের নিজস্ব ছবি, position, size থাকতে পারে। নিয়মটা ওপর থেকে গোনা পত্রিকার স্তূপের মতো — প্রথমে লেখা স্তরটি সবার ওপরে, শেষে লেখাটি নিচে। আর রং থাকতে পারে শুধু শেষ স্তরে, কারণ রং সবসময় সবার নিচে। ধাপে ধাপে দেখুন:

স্তর ১টিশুধু রং
ঢাকা থেকে শুরু — নতুন ব্যাচ
background: #1b2a4a;
স্তর ২টিছবি ওপরে, রং নিচে
ঢাকা থেকে শুরু — নতুন ব্যাচ
background:
  url("cover.jpg") center / cover no-repeat,
  #1b2a4a;
স্তর ৩টিgradient সবার ওপরে
ঢাকা থেকে শুরু — নতুন ব্যাচ
background:
  linear-gradient(to top, rgb(0 0 0 / .8), transparent 75%),
  url("cover.jpg") center / cover no-repeat,
  #1b2a4a;
ক্রম উল্টে দিলামgradient ছবির নিচে চাপা
ঢাকা থেকে শুরু — নতুন ব্যাচ
background:
  url("cover.jpg") center / cover no-repeat,
  linear-gradient(to top, …),   /* লুকিয়ে গেল */
  #1b2a4a;
  1. একটি স্তর — শুধু রং। গাঢ় নীল ব্যাকগ্রাউন্ডে সাদা লেখা পরিষ্কার পড়া যায়। এটাই আমাদের নিরাপত্তা-জাল: ছবি লোড না হলেও এই রং থাকবে।
  2. ছবির স্তর যোগ হলো। কমার আগে ছবি, পরে রং — তাই ছবি ওপরে। ছবি cover হয়ে পুরো বাক্স ঢেকেছে। কিন্তু খেয়াল করুন: ছবির উজ্জ্বল অংশের ওপর সাদা লেখা পড়তে কষ্ট হয়। ছবির কোন অংশ লেখার পেছনে পড়বে, তা পর্দার মাপের ওপর নির্ভর করে — তাই contrast নিশ্চিত করা যায় না।
  3. সবার ওপরে একটি gradient. প্রথম স্তর হিসেবে নিচ থেকে ওপরে ঘন কালো থেকে স্বচ্ছ একটি gradient বসালাম। লেখার ঠিক পেছনে এখন গাঢ় ছায়া, ওপরের দিকে ছবি পরিষ্কার। কোনো ছবি-সম্পাদনা ছাড়াই, শুধু CSS-এ। এটি বাস্তবের প্রায় সব hero ব্যানারের কৌশল।
  4. ক্রম উল্টালে কী হয়? একই তিনটি স্তর, শুধু gradient আর ছবির জায়গা বদল। এখন ছবি সবার ওপরে, আর ছবিটা অস্বচ্ছ — তাই নিচের gradient পুরো চাপা পড়েছে, লেখা আবার কঠিন। মনে রাখুন: কমার আগে যে, ওপরে সে।

এবার নিজে বানান। নিচের ব্যানারে স্তরগুলো নিয়ে খেলুন:

.hero {
  padding: 110px 20px 16px;
  border-radius: 12px;
  color: white;
  font-family: sans-serif;
  background:
    linear-gradient(to top, rgb(0 0 0 / .8), rgb(0 0 0 / 0) 75%),
    url("../image/computer-fundamentals-cover.jpg") center / cover no-repeat,
    #1b2a4a;
}
.hero h2 { margin: 0 0 4px; }
.hero p  { margin: 0; }

ছবির নিচের দিকে গাঢ় ছায়া, তার ওপরে সাদা শিরোনাম আর এক লাইনের বর্ণনা — পরিষ্কার পড়া যায়। চেষ্টা করুন: gradient-এর লাইনটি (প্রথম লাইন আর তার শেষের কমা) মুছে দিন — লেখা পড়তে কতটা কষ্ট হয়? এরপর ছবির URL-এ একটি বানান ভুল করে দিন — ছবি আসবে না, কিন্তু শেষ স্তরের নীল রং থাকবে বলে লেখা তখনো পড়া যাবে। এজন্যই ছবির নিচে সবসময় একটি রং রাখা ভালো অভ্যাস।

৫ · Gradient — রঙের ঢাল: linear, radial, conic আর repeating

Gradient মানে এক রং থেকে আরেক রঙে ধীরে ধীরে বদলে যাওয়া — সন্ধ্যার আকাশে কমলা থেকে বেগুনি যেমন। CSS-এ gradient কোনো রং নয়, এটি একটি ছবি: ব্রাউজার নিজেই হিসাব করে আঁকে। তাই এটি বসে background-image-এ (বা shorthand background-এ), background-color-এ নয়। কোনো ফাইল ডাউনলোড লাগে না, আর যত বড় পর্দাই হোক, কখনো ঝাপসা হয় না।

linear-gradient — সরলরেখায় ঢাল

সবচেয়ে সাধারণ রূপ: linear-gradient(দিক, রং১, রং২, …). দিক না দিলে ওপর থেকে নিচে (to bottom). দিক দুইভাবে লেখা যায় — শব্দে (to right, to top left) বা কোণে। কোণের নিয়ম ঘড়ির কাঁটার মতো: 0deg মানে নিচ থেকে ওপরের দিকে, 90deg মানে ডানে, 180deg নিচে। প্রতিটি রঙের পাশে একটি অবস্থান দেওয়া যায় — একে বলে color stop. আর দুটি রঙের stop এক জায়গায় বসালে মাঝের ঢাল উধাও হয়ে একটি ধারালো সীমা তৈরি হয় — একে বলে hard stop. ডোরাকাটা নকশা, পতাকা, প্রগ্রেস বার — সব এই কৌশলে। ধাপে ধাপে দেখুন:

দুটি রং, কোনো stop নেইপুরো প্রস্থ জুড়ে ঢাল
linear-gradient(90deg, #006a4e, #f4b400)
/* = #006a4e 0%, #f4b400 100% */
stop সরালামঢাল শুধু ৪০%–৬০%-এ
linear-gradient(90deg, #006a4e 40%, #f4b400 60%)
hard stopদুই stop এক জায়গায়
linear-gradient(90deg, #006a4e 50%, #f4b400 50%)
একটি রঙের দুই অবস্থানতিন ডোরার পতাকা
linear-gradient(90deg,
  #1f3a93 0 33.3%, #fbf3e4 33.3% 66.6%, #c0392b 66.6% 100%)
repeating-linear-gradientএকটি নকশা বারবার
repeating-linear-gradient(45deg, #fbf3e4 0 12px, #c0392b 12px 18px)
  1. শুধু দুটি রং। কোনো অবস্থান না দিলে প্রথম রং থাকে 0%-এ, শেষটি 100%-এ, আর মাঝের পুরো দূরত্ব জুড়ে ব্রাউজার ধীরে ধীরে রং মেশায়। 90deg মানে বাঁ থেকে ডানে।
  2. Stop সরালে ঢাল ছোট হয়। এখন 0 থেকে 40% পর্যন্ত খাঁটি সবুজ, 60% থেকে শেষ পর্যন্ত খাঁটি হলুদ, আর মেশানো হয় শুধু মাঝের ২০ শতাংশ জায়গায়। দুই stop যত কাছে, ঢাল তত খাড়া।
  3. দুই stop একই জায়গায় — hard stop. মেশানোর জায়গা শূন্য, তাই রং হঠাৎ বদলায়। চোখে আর gradient মনে হয় না, মনে হয় দুটি আলাদা রঙের টুকরো। (নিয়মটি আরও সহজ: কোনো stop আগেরটির চেয়ে ছোট হলে ব্রাউজার সেটিকে আগেরটির সমান ধরে নেয় — তাই #f4b400 0 লিখলেও একই ফল।)
  4. একটি রঙের দুটি অবস্থান। #1f3a93 0 33.3% মানে “এই রং 0 থেকে 33.3% পর্যন্ত”। তিনটি রং, তিনটি ফালি, সব hard stop — নীল-সাদা-লালের তিন ডোরা, কোনো ছবি ছাড়াই।
  5. repeating — একটি টুকরো বারবার। এখানে ১৮ পিক্সেলের একটি নকশা (১২ পিক্সেল ঘিয়ে, ৬ পিক্সেল লাল) আছে, আর repeating- সেটিকে পুরো বাক্সে বারবার আঁকে। কোণ 45deg হওয়ায় ডোরাগুলো তেরছা — দোকানের সতর্কতা-টেপ বা কাঁথার সেলাইয়ের মতো।

radial আর conic — বৃত্তে আর ঘূর্ণনে

radial-gradient() একটি কেন্দ্র থেকে চারদিকে ছড়ায় — পুকুরে ঢিল ছুড়লে যেমন ঢেউ। আকৃতি circle বা ellipse (ডিফল্ট), আর কেন্দ্র বদলাতে at 30% 40%. বোতামে আলোর ঝলক, ছবির কিনারা অন্ধকার করা (vignette), বা একটি নিখুঁত বৃত্ত আঁকা — সবই radial.

conic-gradient() কেন্দ্রের চারপাশে ঘুরে ঘুরে রং বদলায় — ঘড়ির কাঁটা যেমন ১২টা থেকে ঘুরে আবার ১২টায় আসে। শুরু ওপর থেকে, ঘড়ির কাঁটার দিকে। hard stop-এর সাথে মেলালে এটা একটি পাই চার্ট: conic-gradient(#006a4e 0 40%, #f42a41 0 65%, …) মানে প্রথম ৪০ শতাংশ ঘূর্ণন সবুজ, তারপর ৬৫ পর্যন্ত লাল। আর repeating-radial-gradient(), repeating-conic-gradient() দিয়ে লক্ষ্যভেদের বৃত্ত বা সূর্যরশ্মির মতো নকশা হয়।

.g { height: 56px; margin: 6px 0; padding: 6px;
     border-radius: 8px; font: 13px monospace; }
.g1 { background: linear-gradient(135deg, #006a4e, #f4b400); }
.g2 { background: radial-gradient(circle at 30% 50%,
        #fff 0 8%, #f4b400 30%, #c0392b); }
.g3 { background: repeating-linear-gradient(45deg,
        #fbf3e4 0 10px, #c0392b 10px 14px); }
.g4 { background: linear-gradient(90deg, #1f3a93, #f4b400); }
.g5 { background: linear-gradient(90deg in oklch, #1f3a93, #f4b400); }

.pie {
  width: 140px; aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(#006a4e 0 40%, #f42a41 0 65%,
                             #f4b400 0 85%, #1f3a93 0);
}

ওপরের বাক্সে কোণাকুণি সবুজ থেকে হলুদ; দ্বিতীয়টিতে বাঁ দিকে একটি সাদা আলোর বিন্দু থেকে হলুদ হয়ে লালে ছড়ানো; তৃতীয়টিতে তেরছা ডোরা। চতুর্থ আর পঞ্চমটি একই দুই রং — নীল থেকে হলুদ — কিন্তু চতুর্থটির মাঝখানটা ঘোলাটে ধূসর-বাদামি, আর in oklch দেওয়া পঞ্চমটি মাঝপথে উজ্জ্বল থাকে। সবশেষে চার রঙের একটি পাই চার্ট। চেষ্টা করুন: পাই চার্টে 40%-কে 55% করুন — পরের ফালিগুলো নিজে থেকে সরে যায় কি না দেখুন। তারপর .g5-এ in oklch-এর জায়গায় in oklch longer hue লিখুন — রং রংধনুর মতো উল্টো পথে ঘুরে যাবে।

in oklch অংশটির নাম color interpolation method — দুটি রঙের মাঝের রংগুলো কোন রঙ-জগতে হিসাব হবে (পর্ব ২০-এর oklch মনে করুন)। hex বা rgb() রঙের বেলায় ডিফল্ট sRGB-তে দুটি বিপরীতধর্মী রঙের মাঝে প্রায়ই একটি ধূসর “মরা অঞ্চল” তৈরি হয়; oklch মানুষের চোখের অনুভূতি অনুযায়ী মেশায়। এটি Baseline Newly available (২০২৪ সালে সব প্রধান ব্রাউজারে এসেছে)। পুরোনো ব্রাউজারের জন্য আগে একটি সাধারণ gradient লিখে পরের লাইনে in oklch রূপটি লিখুন — না বুঝলে পুরোনো ব্রাউজার দ্বিতীয় লাইনটি বাদ দেবে, প্রথমটি থাকবে।

পাই চার্টের দুটি সতর্কতা। প্রথমত, conic-gradient শুধু ছবি — screen reader এর ভেতরের সংখ্যা জানে না। তাই উপরের উদাহরণে role="img" আর aria-label দিয়েছি, আর পাশে লেখায় সংখ্যাগুলোও আছে। আসল রিপোর্টে একটি ছোট টেবিল (পর্ব ০৭) আরও ভালো। দ্বিতীয়ত, শুধু রঙে আলাদা করা ফালি বর্ণান্ধ পাঠকের কাছে একরকম লাগতে পারে — লেবেল যোগ করুন।

আরও গভীরে: spec-এ gradient-এর ধরন হলো <image>, কিন্তু এর নিজস্ব কোনো মাপ (intrinsic size) নেই — তাই এটি পুরো background positioning area ভরে দেয়, আর background-size দিয়ে ছোট করলে ব্রাউজার সেটিকে টালির মতো বসায়। এই কারণেই gradient-কে সরাসরি transition দিয়ে মসৃণভাবে বদলানো যায় না: ব্রাউজার দুটি “ছবির” মাঝামাঝি অবস্থা হিসাব করে না, হঠাৎ বদলে দেয়। সমাধান হলো gradient-এর ভেতরের রং বা কোণকে একটি typed custom property বানানো (@property, পর্ব ৩৭)। ইতিহাসও মজার: ২০০৮ সালে WebKit সম্পূর্ণ ভিন্ন গঠনের -webkit-gradient() চালু করেছিল; পরে CSS Images spec আজকের linear-gradient() গঠন ঠিক করে, যেখানে কোণের দিক নিয়েও পুরোনো আর নতুন সংস্করণে উল্টো নিয়ম ছিল — পুরোনো টিউটোরিয়ালের কোণ আজ ভুল দিক দেখাতে পারে।

৬ · বর্ডার — রেখা, গোল কোণ, border-image আর outline

পর্ব ১৯-এ border-কে box model-এর একটি স্তর হিসেবে দেখেছেন। এবার তার চেহারা। প্রতিটি border-এর তিনটি অংশ: প্রস্থ (border-width), ধরন (border-style: solid, dashed, dotted, double, groove, ridge, inset, outset, none) আর রং (border-color, না দিলে লেখার রং — currentColor). shorthand: border: 2px solid #006a4e.

সবচেয়ে প্রচলিত ভুল: শুধু border: 2px বা border-color: red লিখে ভাবা কেন দেখা যাচ্ছে না। কারণ border-style-এর ডিফল্ট none — ধরন না দিলে কোনো রেখাই আঁকা হয় না। প্রতিটি দিক আলাদাও করা যায়: border-left: 6px solid দিয়ে নোটিশ-বক্সের বাঁ পাশে রঙিন দাগ, বা border-bottom দিয়ে শিরোনামের নিচে দাগ। নতুন কোডে border-inline-start-এর মতো logical property-ও দেখবেন, যা আরবি-উর্দুর মতো ডান-থেকে-বাঁ লেখায় নিজে থেকে দিক বদলায় (পর্ব ৩৫)।

border-radius — কোণ গোল করা

border-radius: 12px চারটি কোণাকে ১২ পিক্সেল ব্যাসার্ধের বৃত্তের চাপ দিয়ে গোল করে। চারটি মান দিলে ঘড়ির কাঁটার দিকে — ওপর-বাঁ, ওপর-ডান, নিচ-ডান, নিচ-বাঁ। তিনটি জাদুর ব্যবহার:

  • বৃত্ত: বর্গাকার বাক্সে border-radius: 50%. প্রোফাইল ছবি, আইকনের পটভূমি।
  • পিল (ক্যাপসুল): border-radius: 999px-এর মতো বিশাল মান। ব্রাউজার ব্যাসার্ধকে ছোট দিকের অর্ধেকে নামিয়ে আনে, তাই বাক্স যত চওড়াই হোক, দুই মাথা পুরো গোল। বোতাম আর ট্যাগে খুব চলে।
  • উপবৃত্তাকার কোণ: স্ল্যাশ দিয়ে দুটি মান — border-radius: 40px / 20px মানে আড়াআড়ি ৪০, খাড়া ২০ পিক্সেলের ব্যাসার্ধ। ডিম, পাতা বা ঢেউয়ের আকৃতি এভাবে।

গোল কোণা শুধু border নয় — ব্যাকগ্রাউন্ড, ছায়া আর overflow: hidden দিলে ভেতরের ছবিও সেই বাঁক মেনে কাটা পড়ে। ব্যতিক্রম একটিই: border-image.

border-image — ছবি বা gradient দিয়ে ফ্রেম

border-image একটি ছবিকে নয়টি ভাগে কেটে (চার কোণা, চার পাশ, মাঝ) border-এর জায়গায় বসায়। ছবির জায়গায় gradient দিলে রঙিন বা নকশাদার ফ্রেম হয়। শর্ত দুটি: একটি border-style থাকতে হবে (না হলে প্রস্থ শূন্য), আর border-image থাকলে border-radius কোণা গোল করে না। প্রয়োজন কম পড়ে, কিন্তু কাঁথার পাড়ের মতো ফ্রেমে এটি দারুণ।

div, button { margin: 10px 0; font-family: sans-serif; }
.notice {
  padding: 10px 14px;
  background: #f3f8f5;
  border-left: 6px solid #006a4e;
  border-bottom: 1px dashed #999;
}
.circle {
  width: 64px; aspect-ratio: 1;
  border-radius: 50%;
  border: 3px solid #f42a41;
  background: #fde8ea;
  text-align: center; line-height: 64px; font-size: 22px;
}
.pill  { padding: 8px 22px; border: 0; border-radius: 999px;
         background: #1f3a93; color: white; font-size: 16px; }
.egg   { width: 160px; padding: 20px 0; text-align: center;
         background: #f4b400; border-radius: 40px / 20px; }
.frame { padding: 14px; border: 12px solid;
         border-image: repeating-linear-gradient(45deg,
           #c0392b 0 8px, #fbf3e4 8px 12px, #1f3a93 12px 20px) 12; }

প্রথম লাইনে বাঁ পাশে সবুজ মোটা দাগ আর নিচে ড্যাশ দাগ দেওয়া নোটিশ; তারপর লাল বৃত্তের ভেতরে “রা”; একটি ক্যাপসুল-আকারের নীল বোতাম; উপবৃত্তাকার কোণার হলুদ বাক্স; আর সবশেষে লাল-ঘিয়ে-নীল তেরছা ডোরার ফ্রেম। চেষ্টা করুন: .egg-এ 40px / 20px-কে 50% করুন — পুরো ডিম্বাকৃতি হয়ে যাবে। তারপর .frame-এ border-radius: 20px; যোগ করুন — দেখবেন কোণা গোল হয় না, কারণ border-image রেডিয়াস মানে না।

outline — border-এর মতো দেখতে, কিন্তু আলাদা জিনিস

outline দেখতে border-এর মতো, কিন্তু box model-এর অংশ নয় — কোনো জায়গা নেয় না, পাশের element সরায় না, আর outline-offset দিয়ে বাক্সের বাইরে-ভেতরে সরানো যায়। আধুনিক ব্রাউজারে outline border-radius-এর বাঁকও মেনে চলে। এর আসল কাজ keyboard focus দেখানো: Tab চেপে চলা মানুষ এটি দেখেই বোঝেন তিনি কোথায় আছেন। তাই outline: none লিখে বিকল্প না দেওয়া একটি গুরুতর অ্যাক্সেসিবিলিটি ভুল (:focus-visible নিয়ে বিস্তারিত পর্ব ৩৪ আর ৪৫-এ)।

৭ · ছায়া — box-shadow, text-shadow আর drop-shadow

পর্দা সমতল, তবু কিছু কার্ড “উঁচু” মনে হয়, কিছু বোতাম “চাপা” মনে হয়। এই বিভ্রম তৈরি করে ছায়া। box-shadow-এর পূর্ণ গঠন:

box-shadow: [inset] x-offset y-offset [blur] [spread] [color];
box-shadow: 0 4px 12px 0 rgb(0 0 0 / .25);

শুধু প্রথম দুটি (আড়াআড়ি আর খাড়া সরণ) বাধ্যতামূলক। দুটি মৌলিক সত্য মনে রাখুন। এক: ছায়া কোনো জায়গা নেয় না — layout-এ একটুও প্রভাব ফেলে না, পাশের element সরে না; ছায়া পাশের জিনিসের ওপর বা নিচে শুধু আঁকা হয়। দুই: ছায়া বাক্সের আকার, border-radius-সহ, অনুসরণ করে — ভেতরের লেখা বা ছবির আকৃতি নয়। প্রতিটি মান ধাপে ধাপে যোগ করে দেখুন:

inset 10px 10px 12px 4px rgb(0 0 0 / .3) , 0 1px 2px …
10px 10pxশুধু সরণ
কার্ড
10px 10px 12px+ blur
কার্ড
10px 10px 12px 4px+ spread
কার্ড
… rgb(0 0 0 / .3)+ আধা-স্বচ্ছ রং
কার্ড
inset …ভেতরের ছায়া
কার্ড
কমা দিয়ে কয়েকটি ছায়াস্তরে স্তরে বাস্তব ছায়া
কার্ড
  1. শুধু সরণ। 10px 10px মানে ছায়াটি ১০ পিক্সেল ডানে আর ১০ পিক্সেল নিচে। blur নেই, তাই ধারালো কিনারা — যেন বাক্সের একটি গাঢ় প্রতিলিপি পেছনে রাখা। রং দিইনি, তাই ছায়া লেখার রং (currentColor) নিয়েছে। ঋণাত্মক মান দিলে বাঁয়ে বা ওপরে সরত।
  2. blur যোগ হলো। তৃতীয় মান ছায়ার কিনারা কতটা ঝাপসা হবে। বড় blur মানে নরম, ছড়ানো ছায়া — দূরে থাকা আলোর মতো। blur ঋণাত্মক হতে পারে না।
  3. spread যোগ হলো। চতুর্থ মান ছায়াকে blur-এর আগে চারদিকে বড় (ধনাত্মক) বা ছোট (ঋণাত্মক) করে। ঋণাত্মক spread দিয়ে ছায়াকে শুধু নিচের দিকে উঁকি দেওয়ানো যায়। আর সরণ ও blur শূন্য রেখে শুধু spread দিলে বাক্সের চারপাশে একটি “ফোকাস রিং”-এর মতো রেখা তৈরি হয়।
  4. আধা-স্বচ্ছ রং। আসল ছায়া কখনো খাঁটি কালো হয় না — নিচের রং ভেদ করে দেখা যায়। rgb(0 0 0 / .3) মানে ৩০ শতাংশ অস্বচ্ছ কালো। এবার ছায়া অনেক স্বাভাবিক লাগছে।
  5. inset — ভেতরের ছায়া। শুরুতে inset শব্দটি দিলে ছায়া বাক্সের ভেতরে আঁকা হয়, যেন বাক্সটি পাতার ভেতরে বসে গেছে। ইনপুট ঘর বা চাপা বোতাম দেখাতে কাজে লাগে।
  6. কমা দিয়ে কয়েকটি ছায়া। তিনটি হালকা ছায়া — একটি ছোট ও গাঢ় (কাছের যোগাযোগ-ছায়া), একটি মাঝারি, একটি বড় ও খুব হালকা (দূরের আলো)। প্রথমে লেখা ছায়াটি ওপরে আঁকা হয়, ঠিক ব্যাকগ্রাউন্ড স্তরের নিয়মে। ফল: একটি ভারী ছায়ার চেয়ে অনেক বেশি বাস্তব আর পরিষ্কার “ভাসমান কার্ড”।

text-shadow আর drop-shadow — অন্য দুই ছায়া

text-shadow লেখার প্রতিটি অক্ষরের ছায়া (টাইপোগ্রাফির অংশ, পর্ব ২১)। গঠন প্রায় এক — x y blur color — কিন্তু spread আর inset নেই। ছবির ওপরের লেখায় হালকা text-shadow পড়তে সাহায্য করে, কিন্তু সেটিকে contrast-এর একমাত্র ভরসা বানাবেন না।

filter: drop-shadow() সম্পূর্ণ ভিন্ন জিনিস। এটি element-এর আঁকা আসল রূপ ধরে — স্বচ্ছ অংশ বাদ দিয়ে। তারকা-আকৃতির SVG, স্বচ্ছ পটভূমির PNG লোগো, বা clip-path দিয়ে কাটা আকৃতিতে box-shadow একটি আয়তাকার ছায়া দেয়, কিন্তু drop-shadow আকৃতিটির কিনারা ধরে ছায়া ফেলে। এর spread বা inset নেই। filter-এর পুরো জগৎ (blur, brightness, blend mode) আসবে পর্ব ৪১-এ।

body { background: #eef1f5; font-family: sans-serif; }
.card { margin: 18px 8px; padding: 16px;
        background: white; border-radius: 12px; }
.one  { box-shadow: 0 10px 20px black; }
.layered {
  box-shadow: 0 1px 2px rgb(0 0 0 / .12),
              0 4px 8px rgb(0 0 0 / .10),
              0 16px 32px rgb(0 0 0 / .12);
}
.well { background: #e9ecf1;
        box-shadow: inset 0 2px 6px rgb(0 0 0 / .3); }

svg { width: 90px; margin: 10px; }
.bs { box-shadow: 6px 6px 6px rgb(0 0 0 / .5); }
.ds { filter: drop-shadow(6px 6px 4px rgb(0 0 0 / .5)); }

প্রথম কার্ডের নিচে ঘন কালো, ভারী ছায়া — পুরোনো আর কৃত্রিম দেখায়। দ্বিতীয়টি তিনটি হালকা স্তরে নরমভাবে ভাসছে। তৃতীয়টি পাতার ভেতরে বসে গেছে। নিচের বাঁ তারার পেছনে একটি বর্গাকার ছায়া (box-shadow বাক্স ধরে), ডান তারার ছায়া ঠিক তারার পাঁচ কোণা ধরে (drop-shadow). চেষ্টা করুন: .layered-এর তিনটি লাইনের মধ্যে শেষটি মুছে দিন — “উচ্চতা” কমে যায় কি না দেখুন। তারপর .one-এর black-কে rgb(0 0 0 / .2) করুন — একটু ভালো হয়, কিন্তু স্তরের মতো স্বাভাবিক হয় না।

৮ · সুন্দরের দাম — পারফরম্যান্স আর অ্যাক্সেসিবিলিটি

পর্ব ০১-এ দেখেছেন, ব্রাউজার পাতা দেখাতে কয়েকটি ধাপ পার হয় — layout (কোথায় কী বসবে), paint (পিক্সেলে রং বসানো), তারপর compositing (স্তরগুলো জোড়া দেওয়া)। ব্যাকগ্রাউন্ড, বর্ডার আর ছায়া সবই paint-এর কাজ। সাধারণ অবস্থায় এগুলো খুব দ্রুত। সমস্যা হয় যখন অনেক বড় জায়গা বারবার নতুন করে আঁকতে হয়:

  • বিশাল blur-এর ছায়া: blur যত বড়, প্রতিটি পিক্সেলের জন্য তত বেশি আশেপাশের পিক্সেল মেশাতে হয়। একটি কার্ডে 0 30px 80px সমস্যা নয়; কিন্তু একশো কার্ডের দীর্ঘ তালিকায়, কম দামি ফোনে, প্রতিবার আঁকা লাগলে স্ক্রল ঝাঁকুনি দিতে পারে।
  • ছায়া animate করা: hover-এ box-shadow-এর মান বদলাতে transition দিলে প্রতিটি ফ্রেমে নতুন করে paint হয়। প্রচলিত সমাধান: বড় ছায়াটি একটি ::after pseudo-element-এ আগেই এঁকে রাখা, আর hover-এ শুধু তার opacity বদলানো — opacity বদল সাধারণত compositing ধাপেই সামলানো যায় (পর্ব ৩৮)।
  • background-attachment: fixed: প্রতিটি স্ক্রলে পুরো ব্যাকগ্রাউন্ড নতুন করে আঁকার কারণ হতে পারে, আর মোবাইলে প্রায়ই কাজই করে না। আধুনিক scroll-driven animation (পর্ব ৪২) এই ধরনের ইফেক্টের ভালো বিকল্প।
  • বিশাল ব্যাকগ্রাউন্ড ছবি: hero-র জন্য ৫ মেগাবাইটের ছবি পাতাকে ধীর করে, আর CSS ব্যাকগ্রাউন্ডের ছবি ব্রাউজার একটু দেরিতে খুঁজে পায় (CSS পড়ার পরে)। পাতার মূল ছবি হলে সেটি <img>-এ রাখা প্রায়ই ভালো (পর্ব ৩২ আর ৪৯)।

অনুমান নয়, মেপে দেখুন। DevTools-এর Rendering প্যানেলে “Paint flashing” চালু করলে পাতার যে অংশ নতুন করে আঁকা হচ্ছে তা সবুজ হয়ে জ্বলে ওঠে, আর Performance প্যানেলে দেখা যায় প্রতি ফ্রেমে paint-এ কত মিলিসেকেন্ড যাচ্ছে (পর্ব ৪৭)। নিজের দামি ল্যাপটপে নয়, একটি সাধারণ Android ফোনে পরীক্ষা করুন — আপনার বেশিরভাগ পাঠক সেটাই ব্যবহার করেন।

অ্যাক্সেসিবিলিটি: সাজ যেন অর্থ না হয়ে দাঁড়ায়

  • ছায়া একা সীমানা নয়: Windows-এর contrast থিমের মতো forced colors মোডে ব্রাউজার box-shadow আর text-shadow বাদ দেয়, আর ব্যাকগ্রাউন্ডের রং নিজের রঙে বদলে দেয়। যে বোতাম বা কার্ডের কিনারা শুধু ছায়া দিয়ে বোঝা যেত, তা মিলিয়ে যায়। সমাধান সহজ: একটি স্বচ্ছ border রাখুন — border: 1px solid transparent — forced colors মোডে ব্রাউজার সেটিকে দৃশ্যমান রঙে আঁকে।
  • UI-এর সীমানার contrast: WCAG 2.2-এর একটি শর্ত (1.4.11) বলে, ইনপুট ঘর বা বোতামের সীমানার মতো জরুরি অংশে আশপাশের সাথে অন্তত 3:1 contrast লাগে। খুব হালকা ছায়া বা হালকা ধূসর border দেওয়া ইনপুট ঘর অনেকে খুঁজেই পান না।
  • ছবির ওপর লেখা: সবসময় overlay gradient বা গাঢ় পটভূমি রাখুন, আর ছবির নিচে একটি রং রাখুন যাতে ছবি না এলেও পড়া যায়।
  • রং ছাড়া তথ্য: পাই চার্ট বা লাল-সবুজ ব্যাজে শুধু রঙে অর্থ দেবেন না; লেখা বা আইকনও দিন।

৯ · প্রজেক্ট — নকশিকাঁথা-অনুপ্রাণিত একটি কার্ড

এবার সব একসাথে। নকশিকাঁথার কথা ভাবুন — ঘিয়ে রঙের পুরোনো কাপড়, তার ওপর লাল-নীল সুতোর ছোট ছোট চলমান ফোঁড় (running stitch), মাঝে পদ্ম বা সূর্যের মতো গোল নকশা, চারপাশে পাড়। প্রতিটি অংশ CSS-এর কোনো একটি কৌশল দিয়ে আঁকা যায়, একটিও ছবির ফাইল ছাড়া:

  • ফোঁড়ের দাগ → repeating-linear-gradient (রং, ফাঁক, রং, ফাঁক)
  • পদ্ম বা সূর্য মোটিফ → repeating-conic-gradient-এর পাপড়ির ওপরে radial-gradient-এর কেন্দ্র, border-radius: 50%
  • বুটির নকশা → ছোট radial-gradient বিন্দু, background-size দিয়ে টালির মতো
  • পাড় → border-image-এ তেরছা ডোরা; পাতা থেকে উঁচু ভাব → স্তরে স্তরে box-shadow
<style>
  body { background: #efe6d6; font-family: sans-serif; }
  .kantha { max-width: 320px; margin: 24px auto; background: #fbf3e4; color: #3b1f0e;
    border: 10px solid; border-image: repeating-linear-gradient(45deg,
      #c0392b 0 6px, #fbf3e4 6px 10px, #1f3a93 10px 16px, #fbf3e4 16px 20px) 10;
    box-shadow: 0 2px 4px rgb(0 0 0 / .12), 0 12px 28px rgb(0 0 0 / .15); }
  .band { padding: 22px 0;
    background: radial-gradient(circle, #c0392b 2px, transparent 2.5px) 0 0 / 16px 16px, #f6e7cc; }
  .motif { width: 84px; aspect-ratio: 1; margin: auto; border-radius: 50%;
    background: radial-gradient(circle, #f4b400 0 22%, #fbf3e4 23% 30%, transparent 31%),
      repeating-conic-gradient(#c0392b 0 15deg, #1f3a93 15deg 30deg); }
  .stitch { height: 3px; margin: 0 16px;
    background: repeating-linear-gradient(90deg, #1f3a93 0 10px, transparent 10px 16px); }
  .body { padding: 14px 18px 18px; }
  h2 { margin: 0 0 6px; }
  .price { display: inline-block; margin-top: 8px; padding: 4px 14px;
    border-radius: 999px; background: #1f3a93; color: white; }
</style>
<article class="kantha">
  <div class="band"><div class="motif"></div></div>
  <div class="stitch"></div>
  <div class="body">
    <h2>হাতে সেলাই নকশিকাঁথা</h2>
    <p>যশোরের কারিগরের তৈরি, পুরোনো সুতি কাপড়ে লাল-নীল সুতোর ফোঁড়।</p>
    <span class="price">৳ ৩,২০০</span>
  </div>
</article>

একটি ঘিয়ে রঙের কার্ড, চারপাশে লাল-নীল তেরছা পাড়, ওপরের অংশে লাল বুটির ওপর লাল-নীল পাপড়ির গোল মোটিফ, তার নিচে নীল ড্যাশের একটি “ফোঁড়”, তারপর শিরোনাম, বর্ণনা আর পিল-আকারের দামের ট্যাগ — পুরোটাই CSS, কোনো ছবি নেই। লেখা রাখা হয়েছে সাধারণ ঘিয়ে পটভূমিতে, বুটির ওপর নয় — তাই পড়তে কষ্ট হয় না। নকশাগুলো শুধু সাজ, তাই খালি <div>; অর্থবহ লোগো হলে সেটি HTML-এ SVG বা <img alt> হতো। চেষ্টা করুন: .motif-এ 15deg 30deg-কে 10deg 20deg করুন — পাপড়ি বাড়বে। তারপর .band-এর 16px 16px-কে 10px 10px করুন — বুটি ঘন হবে। নিজের এলাকার শাড়ি বা কাঁথার রঙে বদলে দেখুন।

১০ · AI-এর যুগে — সুন্দর CSS, কিন্তু যাচাই করা

“একটা সুন্দর কার্ড বানিয়ে দাও” বললে AI কয়েক সেকেন্ডেই gradient আর ছায়ায় ভরা কোড দেয়। দেখতে প্রায়ই ভালো। কিন্তু এই বিষয়ে AI-এর কিছু ভুল বারবার দেখা যায়, কারণ সে বহু বছরের পুরোনো টিউটোরিয়াল পড়ে শিখেছে:

AI প্রায়ই যা দেয়সমস্যাযা হওয়া উচিত
-webkit-border-radius, -moz-box-shadow, -webkit-linear-gradientবহু বছর আগে অপ্রয়োজনীয় হয়ে গেছে; পুরোনো gradient-এর কোণের দিকও উল্টোউপসর্গ ছাড়া মূল property
ছবির ওপর সাদা লেখা, কোনো overlay নেইছবির উজ্জ্বল অংশে লেখা অপাঠ্যoverlay gradient স্তর + নিচে রং
gradient লেখা, কোনো fallback নেইব্যাকগ্রাউন্ড না আঁকা হলে লেখা অদৃশ্যসাধারণ color + @supports
শুধু ছায়া দিয়ে বোতাম বা কার্ডের সীমানাforced colors মোডে সীমানা উধাওস্বচ্ছ বা দৃশ্যমান border যোগ
লোগো PNG-তে box-shadowআকৃতির বদলে বর্গাকার ছায়াfilter: drop-shadow()
তথ্যপূর্ণ ছবি CSS ব্যাকগ্রাউন্ডে, বা outline: nonealt নেই; কীবোর্ড ব্যবহারকারী পথ হারান<img alt>; :focus-visible-এ দৃশ্যমান outline

AI-কে কাজ দেওয়ার সময়ই শর্তগুলো বলে দিন — তাহলে যাচাইয়ের কাজ অর্ধেক হয়ে যায়:

একটি পণ্যের কার্ডের HTML আর CSS লিখে দাও। শর্ত: ১. শুধু আধুনিক, উপসর্গ ছাড়া CSS — কোনো -webkit- বা -moz- নয়, কোনো ছবির ফাইল নয়; নকশা gradient দিয়ে। ২. লেখা আর পটভূমির contrast অন্তত 4.5:1 রাখবে, আর কোন রং-জোড়া ব্যবহার করলে সেটা বলবে। ৩. ছায়া হবে ২-৩টি হালকা স্তরে; কার্ডে একটি স্বচ্ছ border রাখবে যাতে forced colors মোডে সীমানা দেখা যায়। ৪. gradient লেখা ব্যবহার করলে fallback রং আর @supports দেবে। ৫. প্রতিটি property কেন দিলে, এক লাইনে বাংলায় ব্যাখ্যা দাও।

AI-এর লেখা ব্যাকগ্রাউন্ড-ছায়ার CSS হাতে পেলে — যাচাইয়ের চেকলিস্ট

পরীক্ষা ও ইন্টারভিউতে — বিশ্ববিদ্যালয়, চাকরি বা ফ্রন্ট-এন্ড ইন্টারভিউর পরীক্ষায় এ ধরনের প্রশ্ন প্রায়ই আসে:

  • background-size: cover আর contain-এর পার্থক্য? — cover পুরো বাক্স ঢাকে (ছবি কাটা যেতে পারে), contain পুরো ছবি দেখায় (ফাঁকা থাকতে পারে); দুটোতেই অনুপাত ঠিক থাকে।
  • একাধিক ব্যাকগ্রাউন্ডে কোনটি ওপরে? — কমা দিয়ে লেখা প্রথমটি ওপরে; background-color সবসময় সবার নিচে, শুধু শেষ স্তরে লেখা যায়।
  • শুধু CSS দিয়ে বৃত্ত আর ডোরা কীভাবে? — বর্গে border-radius: 50%; ডোরার জন্য gradient-এ hard stop বা repeating-linear-gradient.
  • box-shadow আর filter: drop-shadow()-এর পার্থক্য? — প্রথমটি বাক্সের আকার ধরে, spread ও inset আছে; দ্বিতীয়টি স্বচ্ছতা বাদ দিয়ে আসল আকৃতি ধরে।
  • outline আর border-এর পার্থক্য? — border box model-এর অংশ, জায়গা নেয়; outline জায়গা নেয় না, মূলত focus দেখানোর জন্য।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলো আপনাকে property-মুখস্থকারী থেকে নকশা-চিন্তক বানাবে।

প্র ০১CSS-এ border-radius আসার আগে ওয়েবে গোল কোণা কীভাবে বানানো হতো — আর সেই যুগ থেকে কী শেখার আছে?

২০০০-এর দশকের প্রথম ভাগে গোল কোণার একটি বোতাম বানানো ছিল ছোটখাটো প্রকৌশল-প্রকল্প। ডিজাইনার Photoshop-এ বাক্সটি এঁকে চারটি কোণা আলাদা আলাদা ছোট ছবি হিসেবে কেটে নিতেন। তারপর HTML-এ বাক্সের ভেতরে চারটি বাড়তি <div> বা <span> বসিয়ে প্রতিটির ব্যাকগ্রাউন্ডে একটি করে কোণার ছবি দেওয়া হতো। আরও আগে লোকে টেবিলের ৩×৩ ঘরে ছবিগুলো বসাত। লেখা বাড়লে বাক্স বড় হবে, তাই ওপরে-নিচে টেনে বড় করা যায় এমন ছবির কৌশলও লাগত — “sliding doors” নামের একটি বিখ্যাত কৌশলে দুটি ছবি একটির ওপর আরেকটি পিছলে গিয়ে বাক্সের প্রস্থের সাথে মানিয়ে নিত।

দাম ছিল অনেক। প্রতিটি কোণা একটি আলাদা HTTP request; সেকালের ধীর সংযোগে পাতা টুকরো টুকরো আসত। রং বদলাতে হলে সব ছবি নতুন করে কাটতে হতো। ব্যাকগ্রাউন্ডের রং পাল্টালে কোণার ছবির কিনারায় পুরোনো রঙের দাগ দেখা যেত। আর HTML ভরে যেত অর্থহীন div-এ — যাকে আজ আমরা “div-soup” বলি।

তারপর CSS Backgrounds and Borders Level 3-এর খসড়ায় border-radius, box-shadow আর একাধিক ব্যাকগ্রাউন্ড এলো। ব্রাউজারগুলো প্রথমে নিজস্ব উপসর্গ দিয়ে পরীক্ষামূলকভাবে চালু করল — -webkit-border-radius, -moz-border-radius — ফলে কয়েক বছর একই কথা তিন-চারবার লিখতে হতো। পরে spec স্থির হলে উপসর্গ ছাড়া রূপ সব জায়গায় চলতে শুরু করল, আর উপসর্গ ঐতিহাসিক জিনিস হয়ে গেল। আজও AI বা পুরোনো ব্লগ সেগুলো দেয় — এখন আপনি জানেন কেন।

এই গল্পে একটি বড় নকশা-নীতি লুকিয়ে আছে: যা চেহারা, তা CSS-এ; যা অর্থ, তা HTML-এ। কোণার ছবিগুলো চেহারার জিনিস হলেও HTML-কে দূষিত করছিল। CSS যত শক্তিশালী হয়েছে, HTML তত পরিষ্কার হয়েছে। এর সাথে আরেকটি শিক্ষা: ব্রাউজার উপসর্গ দিয়ে নতুন ফিচার আগেভাগে ছেড়ে দেওয়ার পদ্ধতিটি সমস্যা তৈরি করেছিল — ডেভেলপাররা উপসর্গওয়ালা কোডেই অভ্যস্ত হয়ে গিয়েছিলেন। তাই এখন ব্রাউজারগুলো নতুন ফিচার পরীক্ষার জন্য সাধারণত সেটিং-এর পেছনে (feature flag) লুকিয়ে রাখে।

মূল উপলব্ধি: আজকের এক লাইনের border-radius একসময় চারটি ছবি, চারটি div আর অনেক HTTP request ছিল। প্রতিটি নতুন CSS ফিচার আসলে পুরোনো কোনো কষ্টকর কৌশলের অবসান — পুরোনো কৌশল চিনতে পারলে পুরোনো কোড বা AI-এর ভুলও চিনতে পারবেন।

প্র ০২Gradient-কে CSS “রং” না বলে “ছবি” বলে কেন? এই সিদ্ধান্তের কী সুবিধা আর কী অসুবিধা?

রং মানে একটি মান — প্রতিটি পিক্সেলে একই। gradient-এর মান জায়গা ভেদে বদলায়: বাঁয়ে সবুজ, ডানে হলুদ। তাই এটি একটি পুরো ক্ষেত্র (field), এক কথায় একটি ছবি। spec-এর নকশাকারীরা gradient-কে <image> ধরনের মান হিসেবে বসিয়েছেন, যাতে ছবি যেখানে যেখানে বসে, gradient-ও সেখানে বসতে পারে — background-image, border-image, list-style-image, mask, এমনকি কনটেন্টে।

সুবিধা অনেক। প্রথমত, ছবির সব যন্ত্রপাতি বিনা খরচে পাওয়া গেল — repeat, position, size, একাধিক স্তর। এজন্যই background-size: 16px 16px দিয়ে একটি ছোট radial-gradient-কে টালির মতো বিছিয়ে বুটির নকশা হয়। দ্বিতীয়ত, ফাইল ডাউনলোড নেই — একটি নকশাদার ব্যাকগ্রাউন্ড কয়েক কিলোবাইটের PNG-এর বদলে কয়েক ডজন অক্ষরের CSS. তৃতীয়ত, gradient গাণিতিকভাবে আঁকা, তাই রেটিনা পর্দা বা ৪K মনিটরে কখনো ঝাপসা হয় না — ঠিক SVG-এর মতো।

অসুবিধাও আছে। ছবির নিজস্ব কোনো মাপ থাকে, gradient-এর থাকে না — তাই এটি সবসময় পুরো এলাকা ভরে, আর আলাদা মাপ চাইলে background-size লাগে। সবচেয়ে বিরক্তিকর অসুবিধা হলো animation: ব্রাউজার দুটি রঙের মাঝামাঝি মান হিসাব করতে জানে, কিন্তু দুটি ছবির মাঝামাঝি অবস্থা নয়। তাই transition: background 0.3s দিয়ে এক gradient থেকে আরেক gradient-এ যেতে চাইলে মসৃণ বদলের বদলে হঠাৎ লাফ দেয়। বহু বছর ধরে ডেভেলপাররা কৌশল করতেন — দুটি স্তর রেখে ওপরেরটির opacity বদলানো, বা খুব বড় gradient বানিয়ে তার position সরানো। এখন @property দিয়ে gradient-এর ভেতরের একটি রং বা কোণকে typed variable বানালে ব্রাউজার সেই সংখ্যা বা রংটিকে মসৃণভাবে বদলাতে পারে, আর gradient প্রতিটি ফ্রেমে নতুন মানে আঁকা হয় (পর্ব ৩৭)।

মূল উপলব্ধি: কোনো জিনিসকে কোন “ধরনে” বসানো হবে, সেই সিদ্ধান্তই ঠিক করে দেয় সেটি কোথায় ব্যবহার করা যাবে আর কী করা যাবে না। CSS-এর মানের ধরন (type) বুঝলে অনেক রহস্যময় আচরণ যুক্তিসংগত লাগে।

প্র ০৩একটি ভারী ছায়ার চেয়ে কয়েকটি হালকা ছায়ার স্তর বেশি বাস্তব লাগে কেন? আর ডিজাইনের ইতিহাসে ছায়ার জনপ্রিয়তা কীভাবে ওঠানামা করেছে?

উত্তরটা পদার্থবিজ্ঞানে। বাস্তবে একটি বস্তুর নিচে আলো আসে অনেক উৎস থেকে — জানালার সরাসরি আলো, দেয়াল-ছাদ থেকে প্রতিফলিত ছড়ানো আলো। তাই বস্তুর একেবারে গায়ের কাছে একটি ছোট, গাঢ়, ধারালো ছায়া থাকে (যেখানে বস্তু টেবিল ছুঁয়েছে), আর তার চারপাশে একটি বড়, হালকা, নরম ছায়া ধীরে ধীরে মিলিয়ে যায়। বস্তু যত উঁচুতে তোলা হয়, কাছের ছায়া তত হালকা আর দূরের ছায়া তত ছড়ানো হয়। একটিমাত্র box-shadow এই দুই চরিত্র একসাথে দেখাতে পারে না — হয় ধারালো, নয় ঝাপসা। দুই-তিনটি স্তর মিলিয়ে দিলে চোখ সেটিকে বাস্তব আলোর মতো পড়ে।

Google-এর Material Design (২০১৪) এই চিন্তাকে একটি নিয়মে বেঁধেছিল: প্রতিটি উপাদানের একটি “উচ্চতা” (elevation), আর প্রতিটি উচ্চতার জন্য নির্দিষ্ট মাপের দুই-তিন স্তরের ছায়া — একটি কাছের আলোর, একটি পরিবেশের আলোর। ফলে কোন কার্ড কোনটির ওপরে, তা ছায়া দেখেই বোঝা যেত।

ইতিহাসে ছায়ার জনপ্রিয়তা ঢেউয়ের মতো। ২০০০-এর দশকের শেষ দিকে “skeuomorphism” চলত — অ্যাপের বোতাম দেখতে আসল চামড়া, কাঠ, কাচের মতো, প্রচুর ছায়া আর আলোর ঝলকসহ। ২০১৩ সালে Apple iOS 7-এ প্রায় সমতল (flat) নকশায় চলে গেল, আর ওয়েবও ছায়া প্রায় বাদ দিল। কিন্তু সম্পূর্ণ সমতল নকশায় একটি সমস্যা ধরা পড়ল: কোনটা চাপা যায় আর কোনটা শুধু লেখা, বোঝা কঠিন। Material Design আর পরের নকশা-ব্যবস্থাগুলো তাই হালকা, অর্থবহ ছায়া ফিরিয়ে আনে। ২০২০ সালের দিকে “neumorphism” নামে একটি ধারা এসেছিল — পটভূমির একই রঙে একদিকে আলো, অন্যদিকে ছায়া দিয়ে নরম উঁচু-নিচু বোতাম। দেখতে সুন্দর, কিন্তু contrast এত কম যে বোতামের সীমানা প্রায় দেখাই যায় না — অ্যাক্সেসিবিলিটির সমালোচনায় এটি দ্রুত ফিকে হয়।

মূল উপলব্ধি: ছায়া সাজ নয়, একটি ভাষা — “এটি উঁচু, এটি চাপা যায়, এটি অন্যটির ওপরে”। সেই ভাষা বাস্তব আলোর নিয়ম মানলে বিশ্বাসযোগ্য হয়, আর অর্থবহ ও যথেষ্ট contrast-এর হলে সবার কাজে লাগে।

প্র ০৪ছবি বা gradient-এর ওপর লেখার contrast নিশ্চিত করা এত কঠিন কেন? Lighthouse-এর মতো টুল কেন সবসময় ধরতে পারে না?

সাধারণ রঙের পটভূমিতে contrast মাপা সহজ অঙ্ক — লেখার রং আর পটভূমির রং, দুটির আপেক্ষিক উজ্জ্বলতা (relative luminance) থেকে একটি অনুপাত। WCAG 2.2 সাধারণ লেখায় অন্তত 4.5:1 আর বড় লেখায় 3:1 চায়। কিন্তু ছবি বা gradient-এর পটভূমিতে প্রতিটি অক্ষরের পেছনে আলাদা রং। কোনো অক্ষর গাঢ় আকাশের ওপর, পাশেরটি উজ্জ্বল মেঘের ওপর। কোন রঙের সাথে মাপবেন? সঠিক উত্তর: সবচেয়ে খারাপ জায়গাটির সাথে।

আর সমস্যা আরও জটিল হয় রেসপন্সিভ পাতায়। background-size: cover-এ ছবির কোন অংশ লেখার পেছনে পড়বে, তা পর্দার প্রস্থের ওপর নির্ভর করে। ডেস্কটপে লেখার পেছনে গাঢ় গাছপালা, ফোনে একই লেখার পেছনে সাদা দালান। আপনি একটি মাপে পরীক্ষা করে নিশ্চিন্ত হলেন, অথচ অন্য মাপে লেখা অপাঠ্য।

স্বয়ংক্রিয় টুলগুলো সাধারণত element-এর হিসাব করা background-color আর color পড়ে contrast বের করে। পটভূমিতে ছবি বা gradient থাকলে অনেক টুল “নিশ্চিত করা যায়নি, হাতে দেখুন” বলে ছেড়ে দেয়, অথবা শুধু নিচের রং ধরে ভুল আশ্বাস দেয়। DevTools-এর রং-বাছাইয়ের প্যানেল কিছু ক্ষেত্রে পটভূমি থেকে নমুনা নিয়ে অনুমান করে, কিন্তু সেটিও একটি অনুমান। তাই এই জায়গায় মানুষের চোখ আর নীতিই শেষ ভরসা।

নির্ভরযোগ্য নীতি তিনটি। (১) লেখার ঠিক পেছনে এমন একটি স্তর রাখুন, যার contrast আপনি মাপতে পারেন — overlay gradient-এর গাঢ় অংশ, বা লেখার পেছনে আধা-স্বচ্ছ গাঢ় পট্টি। (২) ছবির নিচে একটি রং রাখুন, যার সাথে লেখার contrast ঠিক আছে — ছবি না এলেও পড়া যাবে, আর টুলও অন্তত সেটি মাপতে পারবে। (৩) কয়েকটি পর্দার মাপে, আর forced colors মোডে, নিজে দেখে নিন। gradient লেখার বেলায় নিয়ম একই — gradient-এর সবচেয়ে হালকা রংটি পটভূমির সাথে মিলিয়ে দেখুন।

মূল উপলব্ধি: স্বয়ংক্রিয় টুল যা মাপতে পারে, তা-ই ধরে; ছবির ওপর লেখা তার বাইরে পড়ে। তাই নকশা এমনভাবে করুন যাতে contrast প্রমাণযোগ্য হয় — ভাগ্যের ওপর ছেড়ে দেবেন না।

প্র ০৫নীল থেকে হলুদের gradient-এর মাঝখানটা ঘোলাটে ধূসর হয় কেন? in oklch আসলে কী বদলায়?

Gradient-এর মাঝের রংগুলো ব্রাউজার interpolation করে বানায় — দুই প্রান্তের রঙের সংখ্যাগুলোর মাঝামাঝি মান বের করে। প্রশ্ন হলো, কোন সংখ্যার মাঝামাঝি? ঐতিহ্যগতভাবে ব্রাউজার এটা করত sRGB-তে — লাল, সবুজ, নীলের তিনটি সংখ্যা আলাদা আলাদা মেশাত। নীল (প্রায় 0, 0, 255) আর হলুদ (প্রায় 255, 255, 0)-এর ঠিক মাঝামাঝি দাঁড়ায় প্রায় (128, 128, 128) — অর্থাৎ ধূসর! দুটি বিপরীত রং মেশালে একে অপরকে কাটাকাটি করে। চোখে তাই মাঝখানে একটি নিষ্প্রভ “মরা অঞ্চল” দেখা যায়।

sRGB-র সংখ্যাগুলো মানুষের চোখের অনুভূতির সাথে সমান তালে চলে না। সমান সংখ্যার ধাপ চোখে সমান উজ্জ্বলতার ধাপ মনে হয় না। CSS Color Level 4 আর CSS Images Level 4 তাই gradient-কে বলার সুযোগ দিল কোন রঙ-জগতে মেশাতে হবে: in srgb, in oklab, in oklch, in hsl ইত্যাদি। OKLab আর তার মেরু-রূপ OKLCH (উজ্জ্বলতা, তীব্রতা, রঙের কোণ) তৈরি করা হয়েছে যাতে সংখ্যার সমান ধাপ চোখেও প্রায় সমান লাগে। oklch-তে নীল থেকে হলুদে যাওয়া মানে রঙের চাকায় ঘুরে যাওয়া, পথে তীব্রতা বজায় থাকে — তাই মাঝখানটা উজ্জ্বল থাকে। কোন দিকে ঘুরবে, তা shorter hue (ডিফল্ট) বা longer hue দিয়ে বেছে নেওয়া যায়।

একটি পুরোনো, সম্পর্কিত বাগও আছে। transparent আসলে “স্বচ্ছ কালো” — rgb(0 0 0 / 0). লাল থেকে transparent-এ যেতে গিয়ে কিছু পুরোনো ব্রাউজার মাঝপথে কালচে ধূসর রং দেখাত, কারণ তারা রং আর স্বচ্ছতা আলাদাভাবে মেশাত। spec এখন premultiplied alpha-য় মেশাতে বলে — স্বচ্ছতাকে আগে রঙের সাথে গুণ করে নেওয়া — ফলে আধুনিক ব্রাউজারে এই ধূসর দাগ আর আসে না।

মূল উপলব্ধি: “মাঝামাঝি রং” কোনো একক সত্য নয় — নির্ভর করে কোন মাপকাঠিতে মাপছেন। কম্পিউটারের সুবিধার সংখ্যা আর মানুষের চোখের অনুভূতি আলাদা; ভালো প্রযুক্তি মানুষের দিকটা বেছে নেয়।

অনুশীলন

প্রথমটিতে সামান্য CSS লিখবেন; বাকিগুলো দেখা আর ভাবার কাজ।

  1. এক লাইনে জাতীয় পতাকা: বাংলাদেশের পতাকার দৈর্ঘ্য-প্রস্থের অনুপাত ১০:৬, লাল বৃত্তের ব্যাসার্ধ দৈর্ঘ্যের পাঁচ ভাগের এক ভাগ, আর বৃত্তের কেন্দ্র বাঁ দিক থেকে দৈর্ঘ্যের ৪৫ শতাংশ দূরে, উচ্চতার ঠিক মাঝখানে। একটিমাত্র <div> আর একটি radial-gradient দিয়ে পতাকাটি আঁকুন।

    ২০০ পিক্সেল চওড়া পতাকায় উচ্চতা ১২০, ব্যাসার্ধ ৪০ পিক্সেল, কেন্দ্র (৯০, ৬০)। একটি hard stop-ই যথেষ্ট — কেন্দ্র থেকে ৪০ পিক্সেল পর্যন্ত লাল, তারপর সবুজ। কিনারা যাতে খাঁজকাটা না দেখায়, তাই এক পিক্সেলের ছোট একটি ঢাল রাখা হয়েছে:

    .flag {
      width: 200px;
      aspect-ratio: 10 / 6;
      background: radial-gradient(circle at 45% 50%,
        #f42a41 39.5px, #006a4e 40.5px);
    }

    সবুজ আয়তক্ষেত্রে বাঁ দিকে একটু সরানো লাল বৃত্ত। width বদলালে বৃত্তের অবস্থান শতাংশে থাকায় ঠিক থাকে, কিন্তু ব্যাসার্ধ পিক্সেলে থাকায় ভুল হয়ে যায়। চেষ্টা করুন: width: 300px দিয়ে ব্যাসার্ধ ৫৯.৫ আর ৬০.৫ পিক্সেল করুন। এখানে role="img" আর aria-label দিয়েছি, কারণ পতাকাটি অর্থবহ ছবি।

  2. বাস্তব সাইটের ছায়া খুঁজুন: যেকোনো বড় অনলাইন দোকান বা ব্যাংকের ওয়েবসাইট খুলুন। একটি পণ্য-কার্ড বা ড্রপডাউন মেনুতে ডান-ক্লিক করে Inspect করুন। Styles প্যানেলে box-shadow খুঁজুন — কয়টি স্তর আছে? প্রতিটির blur আর স্বচ্ছতা কত? মানের পাশের ছোট আইকনে চেপে shadow editor খুলে মান বদলে দেখুন।

    বেশিরভাগ আধুনিক সাইটে দুই বা তিন স্তরের ছায়া পাবেন, প্রতিটির স্বচ্ছতা খুব কম — প্রায়ই ০.০৫ থেকে ০.২-এর মধ্যে। একটি ছোট সরণ আর ছোট blur (কাছের ছায়া), একটি বড় সরণ আর বড় blur (দূরের ছায়া)। অনেক সাইটে মানগুলো --shadow-md-এর মতো CSS variable-এ রাখা থাকে (পর্ব ৩৩) — পুরো সাইটে একই “উচ্চতার ভাষা” বজায় রাখতে। ড্রপডাউন বা মডালের ছায়া সাধারণত কার্ডের চেয়ে বড়, কারণ সেগুলো আরও “উঁচুতে” ভাসে।

  3. forced colors পরীক্ষা: DevTools খুলে Rendering প্যানেলে “Emulate CSS media feature forced-colors”-কে active করুন (Windows-এ Settings → Accessibility → Contrast themes চালু করেও দেখা যায়)। এই পর্বের ছায়ার লাইভ এডিটরের কার্ডগুলো আর নকশিকাঁথার কার্ড কেমন দেখায়? কী হারিয়ে যায়, কী থাকে?

    ছায়ার কার্ডগুলোর সব box-shadow উধাও হয়, আর সাদা পটভূমি সিস্টেমের রঙে বদলে যায় — ফলে কার্ডের সীমানা প্রায় বোঝা যায় না। নকশিকাঁথার কার্ডে border থাকায় ফ্রেম একটি সাধারণ রেখা হিসেবে টিকে থাকে, কিন্তু gradient-এর নকশা (পাড়, বুটি, মোটিফ) হারিয়ে যেতে পারে — ব্রাউজারভেদে ফল একটু আলাদা। এজন্যই নিয়ম: ছায়ার পাশাপাশি একটি border রাখুন (দরকার হলে transparent). আর @media (forced-colors: active) দিয়ে এই মোডের জন্য আলাদা ছোট সমন্বয়ও লেখা যায় — তবে ব্যবহারকারীর বেছে নেওয়া রং বাতিল করার জন্য নয়, শুধু হারিয়ে যাওয়া সীমানা ফিরিয়ে আনার জন্য।

  4. ধীর স্ক্রলের তদন্ত: একটি দোকানের পাতায় ২০০টি পণ্য-কার্ড, প্রতিটিতে box-shadow: 0 30px 90px rgb(0 0 0 / .4), আর hover-এ ছায়া বড় করার জন্য transition: box-shadow .3s. কম দামি ফোনে স্ক্রল ঝাঁকুনি দিচ্ছে। কী কী কারণ হতে পারে, আর আপনি কী বদলাবেন?

    সম্ভাব্য কারণ: (১) প্রতিটি ছায়ার ৯০ পিক্সেলের blur বিশাল এলাকা জুড়ে — কার্ডের চেয়ে অনেক বড় জায়গা আঁকতে হয়, আর ২০০টি কার্ডে সেই খরচ বহুগুণ। (২) স্ক্রলের সময় আঙুলের নিচে কার্ডগুলোতে hover শুরু-শেষ হলে প্রতিটি ফ্রেমে ছায়া নতুন করে আঁকা লাগে। সমাধান: ছায়া ছোট আর স্তরে স্তরে করুন (যেমন 0 1px 2px আর 0 8px 24px, কম স্বচ্ছতায়); hover-এর বড় ছায়াটি ::after-এ আগেই এঁকে শুধু তার opacity বদলান; টাচ-স্ক্রিনে hover ইফেক্ট সীমিত রাখুন (@media (hover: hover)). তারপর DevTools-এর Paint flashing আর Performance প্যানেলে আগে-পরে মেপে নিশ্চিত হোন — অনুমানে নয়।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি বাক্স আঁকার সময় কোনটি সবার নিচে, কোনটি সবার ওপরে — নিচ থেকে ওপরে সাজান (▲▼ চেপে সরান)

  1. বাইরের box-shadow
  2. background-color
  3. কমা দিয়ে লেখা শেষ background-image স্তর
  4. কমা দিয়ে লেখা প্রথম background-image স্তর
  5. border
  6. বাক্সের ভেতরের লেখা (content)

একটি চওড়া ছবিকে বর্গাকার বাক্সের পটভূমিতে এমনভাবে বসাতে চান যাতে পুরো ছবিটাই দেখা যায়, অনুপাত না বদলায়। কোন মান?

  • background-size: cover
  • background-size: contain
  • background-size: 100% 100%
  • background-size: auto

background: url(a.png), url(b.png), #eee; — কোনটি দর্শকের সবচেয়ে কাছে (সবার ওপরে) আঁকা হবে?

  • a.png
  • b.png
  • #eee
  • তিনটি সমানভাবে মিশে যাবে

linear-gradient(90deg, red 50%, blue 50%) দেখতে কেমন হবে?

  • বাঁ থেকে ডানে লাল ধীরে ধীরে নীলে মিশে যাবে
  • ওপরের অর্ধেক লাল, নিচের অর্ধেক নীল
  • বাঁ অর্ধেক খাঁটি লাল, ডান অর্ধেক খাঁটি নীল, মাঝে ধারালো সীমা
  • ঘোষণাটি অবৈধ, তাই কিছুই আঁকা হবে না

১০০ × ১০০ পিক্সেলের একটি বর্গাকার <div>-কে নিখুঁত বৃত্ত বানাতে কোনটি লিখবেন?

  • border-style: circle
  • background: radial-gradient(circle, red, blue)
  • border-radius: 10px
  • border-radius: 50%

একটি কার্ডে box-shadow: 0 20px 40px rgb(0 0 0 / .3) যোগ করলে তার নিচের element-এর অবস্থানে কী হবে?

  • নিচের element ২০ পিক্সেল নিচে সরে যাবে
  • কিছুই সরবে না — ছায়া কোনো জায়গা নেয় না
  • কার্ডের margin নিজে থেকে ৪০ পিক্সেল বাড়বে
  • ছায়াটি কার্ডের ভেতরে কেটে বাদ দেওয়া হবে

স্বচ্ছ পটভূমির একটি তারকা-আকৃতির PNG লোগোর নিচে এমন ছায়া চান, যা তারার কিনারা মেনে চলবে। কোনটি ব্যবহার করবেন?

  • box-shadow
  • text-shadow
  • filter: drop-shadow()
  • box-shadow: inset …

শিরোনামে background-clip: text আর color: transparent দিয়ে gradient লেখা বানানো হয়েছে। অ্যাক্সেসিবিলিটির দিক থেকে সবচেয়ে জরুরি সাবধানতা কোনটি?

  • একটি সাধারণ রং fallback রাখা, @supports দিয়ে মোড়ানো আর হালকা অংশের contrast মাপা
  • শিরোনামে aria-hidden="true" দেওয়া
  • শুধু -webkit- উপসর্গ যোগ করা
  • শিরোনামটি ছবি বানিয়ে <img>-এ বসানো

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. ব্যাকগ্রাউন্ড = নিচে একটি রং + ওপরে ছবির স্তর; কমা দিয়ে লেখা প্রথম স্তর সবার ওপরে। shorthand-এ position আর size-এর মাঝে /.
  2. cover বাক্স ভরে (কাটা যায়), contain ছবি পুরো দেখায় (ফাঁকা থাকে); তথ্যপূর্ণ ছবি CSS-এ নয়, <img alt>-এ।
  3. Gradient একটি ছবি: linear (কোণ, color stop, hard stop), radial, conic (পাই চার্ট), repeating; in oklch মাঝখান উজ্জ্বল রাখে।
  4. border-style ছাড়া border নেই; border-radius: 50% বৃত্ত, বড় মান পিল, / উপবৃত্ত; outline জায়গা নেয় না, focus-এর জন্য।
  5. ছায়া জায়গা নেয় না; কয়েকটি হালকা স্তর বাস্তব; আকৃতি ধরতে drop-shadow(); বিশাল blur আর animate করা ছায়া পারফরম্যান্সে দামি; ছায়া একা সীমানা নয়।

পরের পর্বে: বাক্স সাজানো শিখলেন; এবার বাক্সগুলো পাতায় কীভাবে বসে। Normal flow, display-এর block-inline-এর খেলা আর content বাক্স থেকে উপচে পড়লে overflow — শুরু হচ্ছে লেআউটের মডিউল।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান