এই পর্বে যা শিখবেন
- ব্রাউজার কীভাবে font stack থেকে প্রতিটি অক্ষরের ফন্ট বাছে, আর generic family আসলে কী
font-size,rem, type scale,font-weight,font-styleআরfontshorthand-এর ফাঁদ- এককহীন
line-height, লাইনের দৈর্ঘ্য (ch),text-align,text-decoration,letter-spacing-এর মতো লেখা সাজানোর property - লাইন ভাঙার নিয়ন্ত্রণ —
white-space,text-wrap,hyphens,overflow-wrap @font-face,woff2,font-display, Google Fonts বনাম নিজের সার্ভার, variable font আরfont-size-adjust
১ · টাইপোগ্রাফি মানে পড়ার আরাম — কেন লেখার নকশাই ওয়েবের নকশা
একটি খবরের সাইট, bKash-এর সাহায্যের পাতা, অনলাইন দোকানের পণ্যের বিবরণ, সরকারি নোটিশ — সবখানে আসল জিনিস হলো লেখা। লেখাকে কোন ফন্টে, কত বড়, কতটা ফাঁক রেখে, কত লম্বা লাইনে সাজাবেন — এই কারিগরির নাম typography (টাইপোগ্রাফি)। ২০০৬ সালে ডিজাইনার Oliver Reichenstein একটি প্রবন্ধে লিখেছিলেন, “Web design is 95% typography” — ওয়েব ডিজাইনের প্রায় পুরোটাই আসলে লেখার নকশা। সংখ্যাটা মাপা নয়, কিন্তু মূল কথাটা আজও সত্য।
পরীক্ষার খাতার কথা ভাবুন। দুজন পরীক্ষার্থী একই উত্তর লিখলেন। একজনের হাতের লেখা পরিষ্কার, লাইন সোজা, অনুচ্ছেদের মাঝে ফাঁক। আরেকজনের লেখা গায়ে গায়ে, লাইন পুরো পাতা জুড়ে, কোথায় এক প্রশ্ন শেষ আর অন্যটি শুরু বোঝা যায় না। পরীক্ষক কার খাতা পড়ে বেশি খুশি হবেন? তথ্য একই, কিন্তু পড়ার কষ্ট আলাদা। ওয়েবে পাঠক আরও অধৈর্য — কষ্ট হলে খাতা বন্ধ নয়, ট্যাব বন্ধ করে দেন।
ভালো টাইপোগ্রাফির তিনটি কাজ: পড়া যায় (legibility — প্রতিটি অক্ষর আলাদা করে চেনা যায়), পড়তে আরাম (readability — অনেকক্ষণ পড়লেও চোখ ক্লান্ত হয় না) আর গুরুত্ব বোঝায় (hierarchy — কোনটা শিরোনাম, কোনটা মূল কথা, কোনটা পাদটীকা, এক নজরে বোঝা যায়)। চতুর্থ একটি কাজও আছে — সবার জন্য। চোখে কম দেখেন এমন পাঠক ব্রাউজারে লেখা বড় করেন, ডিসলেক্সিয়া আছে এমন পাঠক লাইনের ফাঁক বাড়ান। আপনার CSS যেন এসব বদল সামলাতে পারে, সেটা accessibility-র অংশ, আর WCAG 2.2-এর কয়েকটি নিয়ম সরাসরি এ নিয়েই (অংশ ৫-এ দেখবেন)।
লেখার প্রায় সব CSS property উত্তরাধিকার সূত্রে সন্তান element-এ যায় (পর্ব ১৮-এর inheritance). তাই টাইপোগ্রাফির বেশিরভাগ কাজ হয় একবারে, ওপরের স্তরে — html বা body-তে ফন্ট, আকার আর লাইনের উচ্চতা; তারপর শুধু যেখানে আলাদা দরকার (শিরোনাম, কোড, ছোট লেখা) সেখানে বদল। প্রতিটি p-তে আলাদা করে ফন্ট লেখা মানে ভুল জায়গায় পরিশ্রম।
বাংলার নিজস্ব বিষয়গুলো — যুক্তাক্ষর, বাংলা ওয়েব ফন্টের তালিকা, বাংলায় কেন বেশি line-height লাগে, কেন বাংলায় italic আর letter-spacing নয় — পর্ব ১৪-এ (ওয়েবে বাংলা) বিস্তারিত আছে। এখানে আমরা সাধারণ টাইপোগ্রাফির নিয়ম দেখব, বাংলা আর ইংরেজি দুই লেখা পাশাপাশি রেখে।
২ · font-family — ফন্টের তালিকা আর পাঁচটি generic family
font-family বলে লেখা কোন ফন্টে দেখাবে। কিন্তু আপনি জানেন না পাঠকের যন্ত্রে কোন ফন্ট আছে — কারও Windows, কারও পুরোনো Android, কারও iPhone. তাই এখানে একটি নাম নয়, একটি তালিকা দেওয়া হয়, যাকে বলে font stack. ব্রাউজার বাঁ থেকে ডানে চেষ্টা করে; প্রথমটি না পেলে বা তাতে কোনো অক্ষর না থাকলে পরেরটি (পর্ব ১৪-এর font fallback).
body {
/* নির্দিষ্ট ফন্ট আগে, generic family সবার শেষে */
font-family: "Hind Siliguri", "Segoe UI", Roboto, sans-serif;
}
code, pre {
font-family: ui-monospace, Consolas, "Courier New", monospace;
}নিয়ম দুটি: নামের মধ্যে ফাঁকা জায়গা থাকলে উদ্ধৃতিচিহ্ন দিন ("Segoe UI"); আর তালিকার শেষে সবসময় একটি generic family. generic family কোনো নির্দিষ্ট ফন্ট নয়, একটি ধরন — “যেকোনো একটি sans-serif ফন্ট দাও”। কোন আসল ফন্ট আসবে, তা ব্রাউজার আর অপারেটিং সিস্টেম ঠিক করে। প্রধানগুলো:
serif
অক্ষরের মাথায়-পায়ে ছোট টান (serif) থাকে — Times New Roman, Georgia. ছাপা বই আর সংবাদপত্রের ঐতিহ্য। লম্বা প্রবন্ধে অনেকে পছন্দ করেন।
বই, প্রবন্ধsans-serif
“sans” মানে ছাড়া — টান নেই, সরল রেখা: Arial, Segoe UI, Roboto. পর্দায় পরিষ্কার, তাই অ্যাপ আর বেশিরভাগ ওয়েবসাইটের মূল লেখা।
মূল লেখা, অ্যাপmonospace
প্রতিটি অক্ষর সমান চওড়া — i আর m একই জায়গা নেয়। কোড, টার্মিনাল, টেবিলের সংখ্যা মেলাতে। 0 আর O, 1 আর l আলাদা চেনা যায়।
কোডsystem-ui
অপারেটিং সিস্টেম নিজের মেনু আর বোতামে যে ফন্ট ব্যবহার করে — Windows-এ Segoe UI, Mac-এ San Francisco, Android-এ Roboto. কোনো ডাউনলোড ছাড়াই “নিজের অ্যাপের মতো” চেহারা।
Baseline Widely availableপুরোনো cursive আর fantasy-তে কোন ফন্ট আসবে তার ঠিক নেই, তাই প্রায় ব্যবহার হয় না। নতুন ui-monospace, ui-sans-serif, ui-serif, ui-rounded সিস্টেমের নিজস্ব ধরন চায়; এগুলো এখনো সব ব্রাউজারে কাজ করে না (মূলত Apple-এর ব্রাউজারে), তাই এরপরে সবসময় একটি সাধারণ generic রাখুন। নিচের প্রিভিউতে নিজের যন্ত্রে দেখুন:
<style>
p { font-size: 22px; margin: 6px 0; }
small { display: block; font: 12px monospace; color: #666; }
</style>
<p style="font-family: serif"><small>serif</small>Typography 0O1l — পড়ার আরাম</p>
<p style="font-family: sans-serif"><small>sans-serif</small>Typography 0O1l — পড়ার আরাম</p>
<p style="font-family: monospace"><small>monospace</small>Typography 0O1l — পড়ার আরাম</p>
<p style="font-family: system-ui"><small>system-ui</small>Typography 0O1l — পড়ার আরাম</p>
<p style="font-family: cursive"><small>cursive</small>Typography 0O1l — পড়ার আরাম</p>
<p style="font-family: 'No Such Font'"><small>'No Such Font' (generic নেই)</small>Typography 0O1l — পড়ার আরাম</p>ইংরেজি অংশে পাঁচটি আলাদা চেহারা দেখবেন: serif-এ পায়ের টান, sans-serif-এ সরল, monospace-এ সব অক্ষর সমান চওড়া (0 আর O, 1 আর l-এর পার্থক্য খেয়াল করুন), system-ui-তে আপনার সিস্টেমের মেনুর ফন্ট, cursive-এ হাতের লেখার ধাঁচ। কিন্তু বাংলা অংশ প্রায় সব লাইনে এক রকম! কারণ generic family প্রতিটি লিপির জন্য আলাদা ফন্টে মেলে, আর অনেক সিস্টেমে বাংলার একটিই ফন্ট (Windows-এ সাধারণত Nirmala UI) — serif বা cursive বাংলা ফন্ট নেই। শেষ লাইনে ফন্টের নাম ভুল আর generic নেই, তাই ব্রাউজার নিজের ডিফল্ট ফন্ট নিয়েছে (সাধারণত serif). চেষ্টা করুন: শেষ লাইনে 'No Such Font'-এর পরে , monospace যোগ করুন — এবার আপনার পছন্দের ধরন আসবে।
ব্রাউজার আসলে কীভাবে ফন্ট বাছে — প্রতিটি অক্ষরের জন্য আলাদা
একটি লাইনে ইংরেজি, বাংলা, টাকার চিহ্ন আর একটি emoji থাকলে কী হয়? ব্রাউজার পুরো লাইনের জন্য একটি ফন্ট বাছে না — প্রতিটি অক্ষরের জন্য তালিকা ধরে খোঁজে। ধাপে ধাপে দেখুন:
- লেখা
Price ৳৫০ 😀তিন লিপি, এক লাইন - "Inter"
P r i c eশুধু ইংরেজি আছে - "Hind Siliguri"
৳ ৫ ০বাংলা অংশ - sans-serif
?emoji নেই - সিস্টেমের খোঁজ
emoji ফন্টনা পেলে □
- লেখা আর তালিকা. CSS বলছে: আগে Inter (একটি ইংরেজি ওয়েব ফন্ট), তারপর Hind Siliguri, শেষে sans-serif. লাইনে আছে ইংরেজি, বাংলা অঙ্ক, টাকার চিহ্ন আর একটি হাসিমুখ — চারটি আলাদা ধরনের অক্ষর।
- প্রথম ফন্ট. ব্রাউজার প্রতিটি অক্ষরের জন্য প্রথমে Inter দেখে। ইংরেজি অক্ষর আর ফাঁকা জায়গা এখানেই পাওয়া গেল। এজন্যই ইংরেজি ফন্ট আগে আর বাংলা ফন্ট পরে লিখলে দুই লিপি দুই ফন্টে আসে — ইংরেজির চেহারা আপনার পছন্দমতো, বাংলাও ঠিক থাকে।
- দ্বিতীয় ফন্ট. Inter-এ বাংলা অক্ষর নেই, তাই ৳, ৫, ০-এর জন্য ব্রাউজার পরের নাম Hind Siliguri-তে যায়। ফন্টটি ওয়েব ফন্ট হলে এবং
unicode-rangeথাকলে, পাতায় বাংলা অক্ষর আছে দেখেই তবে বাংলা অংশের ফাইল নামে। - generic family. emoji দুটি ফন্টের কোনোটিতে নেই। এবার
sans-serif— সিস্টেম যে ফন্টটি দেয় (যেমন Arial), তাতেও emoji নেই। তালিকা শেষ, কিন্তু ব্রাউজার এখনো হাল ছাড়েনি। - সিস্টেমের শেষ খোঁজ. তালিকা ফুরোলে ব্রাউজার নিজে সিস্টেমের সব ফন্টে খোঁজে, যার একটিতে অক্ষরটি আছে — emoji-র জন্য সাধারণত সিস্টেমের রঙিন emoji ফন্ট। কোথাও না পেলে ফাঁকা বাক্স, যাকে বলে tofu. DevTools-এর Elements → Computed-এর নিচে “Rendered Fonts” দেখলে জানবেন আসলে কোন ফন্ট কতটি অক্ষর এঁকেছে।
System font stack — ডাউনলোড ছাড়া পরিষ্কার লেখা
GitHub-এর মতো অনেক বড় সাইট আর অ্যাপ মূল লেখার জন্য কোনো ওয়েব ফন্ট নামায় না; তারা পাঠকের নিজের সিস্টেম ফন্ট ব্যবহার করে। এতে পাতা দ্রুত খোলে, লেখা কখনো ফন্টের অপেক্ষায় আটকায় না, আর সিস্টেম ফন্টগুলো পর্দার জন্য যত্ন করে বানানো। আজকের সহজ রূপ: font-family: system-ui, sans-serif; — বাংলা লেখার জন্য সিস্টেম নিজেই নিজের বাংলা ফন্ট এনে দেয়। সীমাবদ্ধতা একটাই: চেহারা যন্ত্রভেদে আলাদা, ব্র্যান্ডের নির্দিষ্ট চেহারা পাবেন না।
৩ · আকার আর ওজন — font-size, rem, type scale, font-weight, font-style
font-size লেখার আকার। পর্ব ২০-এ একক দেখেছেন; লেখার জন্য সারকথা এই: ব্রাউজারের ডিফল্ট সাধারণত 16px, আর পাঠক চাইলে ব্রাউজারের সেটিংসে সেটি বড় করতে পারেন (চোখে কম দেখেন এমন অনেকেই করেন)। rem (root em) মানে মূল html element-এর font-size-এর গুণিতক — 1rem = সাধারণত 16px, কিন্তু পাঠক ডিফল্ট 20px করলে 1rem = 20px. তাই লেখার আকার rem-এ দিন, স্থির px-এ নয় — তাহলে পাঠকের পছন্দ মানা হয়। em হলো মা-element-এর font-size-এর গুণিতক; ভেতরে ভেতরে বসালে গুণ জমতে থাকে (0.8em-এর ভেতরে 0.8em = মূল আকারের 0.64 গুণ), তাই em কাজে লাগে মূলত padding বা আইকনের মতো “এই লেখার সাথে মিলিয়ে” মাপে।
html { font-size: 62.5%; } কৌশল নিয়ে সাবধান। পুরোনো টিউটোরিয়ালে দেখবেন, হিসাব সহজ করতে root-কে 10px বানানো হয় (1.6rem = 16px). এতে পাঠকের সেটিং মানা হয় ঠিকই, কিন্তু কোনো তৃতীয় পক্ষের উইজেট rem ধরে লেখা হলে সেটি হঠাৎ ছোট হয়ে যায়। আজ বেশিরভাগ দল root-কে ছুঁয়েই দেখে না — 1rem = ডিফল্ট, আর মাপ লেখে 1.125rem-এর মতো।
Type scale — আকারগুলোর মধ্যে একটি ছন্দ
শিরোনাম কত বড় হবে, ইচ্ছেমতো 23px, 31px, 17px বসালে পাতা অগোছালো লাগে। ডিজাইনাররা তাই একটি type scale (বা modular scale) ব্যবহার করেন: মূল আকার থেকে প্রতিটি ধাপে একই অনুপাতে গুণ। অনুপাত 1.25 হলে: 1rem → 1.25rem → 1.563rem → 1.953rem → 2.441rem (16 → 20 → 25 → 31.25 → 39px). গানের সুরের মতো — স্বরগুলোর মধ্যে নির্দিষ্ট অনুপাত থাকলে কানে মিষ্টি লাগে। নিচে অনুপাতটি একটি CSS variable-এ রাখা আছে (CSS variable বিস্তারিত পর্ব ৩৩-এ), তাই একটি সংখ্যা বদলালেই পুরো স্কেল বদলায়:
:root { --ratio: 1.25; }
body { font: 1rem/1.6 system-ui, sans-serif; margin: 8px; }
h1, h2, h3, h4 { line-height: 1.25; margin: 0.4em 0 0.2em; }
h4 { font-size: calc(1rem * var(--ratio)); }
h3 { font-size: calc(1rem * var(--ratio) * var(--ratio)); }
h2 { font-size: calc(1rem * var(--ratio) * var(--ratio) * var(--ratio)); }
h1 { font-size: calc(1rem * var(--ratio) * var(--ratio) * var(--ratio) * var(--ratio)); }
small { font-size: calc(1rem / var(--ratio)); }ছয়টি স্তর — h1 থেকে ছোট লেখা পর্যন্ত — প্রতিটি পরেরটির ঠিক 1.25 গুণ। চোখে একটি পরিষ্কার সিঁড়ি দেখা যায়: কোনটা বড় শিরোনাম, কোনটা উপশিরোনাম, ভাবতে হয় না। চেষ্টা করুন: --ratio-কে 1.5 করুন — নাটকীয়, পোস্টারের মতো স্কেল, বড় পর্দায় মানায়। তারপর 1.125 করুন — শান্ত, ঘন স্কেল, ফোন বা ড্যাশবোর্ডে মানায়। h-এর margin em-এ দেওয়ায় বড় শিরোনামের চারপাশের ফাঁকও নিজে বেড়েছে।
font-weight — 100 থেকে 900
font-weight লেখার মোটা-চিকন ভাব। মান 100 (Thin) থেকে 900 (Black), ১০০-র ধাপে; normal = 400, bold = 700. bolder আর lighter মা-element-এর ওজনের তুলনায় লেখাকে একটু মোটা বা চিকন করে (স্পেসিফিকেশনের একটি নির্দিষ্ট সারণি ধরে)। কিন্তু একটি জিনিস মনে রাখুন: ফন্টে যে ওজনগুলো আছে, ব্রাউজার শুধু সেগুলোই দেখাতে পারে। কোনো ফন্টে শুধু 400 আর 700 থাকলে 300 চাইলে আসবে 400, 600 চাইলে 700 — CSS স্পেসিফিকেশনে কাছের ওজন বাছার নির্দিষ্ট নিয়ম আছে। আর ফন্টে কোনো bold-ই না থাকলে ব্রাউজার অক্ষর কৃত্রিমভাবে মোটা করে (একে বলে faux bold; font-synthesis property দিয়ে বন্ধ করা যায়) — দেখতে কিছুটা থ্যাবড়া।
<style>
p { font-family: system-ui, sans-serif; font-size: 22px; margin: 2px 0; }
</style>
<p style="font-weight: 100">100 Thin — রিকশা</p>
<p style="font-weight: 300">300 Light — রিকশা</p>
<p style="font-weight: 400">400 Regular — রিকশা</p>
<p style="font-weight: 600">600 Semibold — রিকশা</p>
<p style="font-weight: 700">700 Bold — রিকশা</p>
<p style="font-weight: 900">900 Black — রিকশা</p>
<p style="font-style: italic">italic — Dhaka ঢাকা</p>ইংরেজি অংশে কয়টি আলাদা ওজন দেখছেন, তা আপনার সিস্টেম ফন্টের ওপর নির্ভর করে — Windows-এর Segoe UI-তে কয়েকটি ওজন আছে, তাই অনেকগুলো আলাদা দেখায়; কোনো ফন্টে শুধু দুটি থাকলে ছয় লাইন দুই দলে ভাগ হয়ে যাবে। শেষ লাইনে ইংরেজি সত্যিকারের italic (আলাদা নকশার হেলানো অক্ষর), কিন্তু বাংলা শুধু কৃত্রিমভাবে হেলানো — বাংলা ফন্টে italic রূপ সাধারণত থাকে না। চেষ্টা করুন: একটি লাইনে 650 বা 350 দিন — কোন ওজনের সাথে মিলে যায় দেখুন। তারপর শেষ লাইনের style-এ font-synthesis: none; যোগ করুন — বাংলা আর কৃত্রিমভাবে হেলবে না।
font-style-এর মান তিনটি: normal, italic (ফন্টের আলাদা করে আঁকা বাঁকা রূপ — ইংরেজিতে a, f-এর আকারই বদলে যায়) আর oblique (একই অক্ষর শুধু হেলানো)। মনে রাখুন, <em> বা <i> HTML-এ অর্থ দেয় (পর্ব ০৪), আর font-style শুধু চেহারা — বাংলা পাতায় em { font-style: normal; font-weight: 600; } লিখে অর্থ রেখে চেহারা বদলানো যায়।
৪ · font shorthand — এক লাইনে সব, কিন্তু ফাঁদসহ
ফন্টের কয়েকটি property একটি লাইনে লেখা যায় font shorthand দিয়ে। এর নিজস্ব কঠোর ক্রম আছে। নিচের লাইনটির প্রতিটি অংশ ধাপে ধাপে দেখুন:
italic— font-style. ঐচ্ছিক অংশগুলো (style,small-caps, weight, প্রস্থ) আসে আকারের আগে, নিজেদের মধ্যে যেকোনো ক্রমে। না লিখলে মান হয়normal.600— font-weight. এটিও ঐচ্ছিক, আকারের আগে।boldশব্দটিও চলে। খেয়াল করুন, এখানে একক নেই — 600 মানে ওজন, আকার নয়।1.125rem— font-size, বাধ্যতামূলক. আকার না লিখলে পুরো ঘোষণাটাই অবৈধ, ব্রাউজার চুপচাপ উপেক্ষা করে। 1.125rem মানে সাধারণত 18px./1.6— line-height. আকারের ঠিক পরে স্ল্যাশ দিয়ে, ঐচ্ছিক। ছাপাখানার পুরোনো রীতি থেকে এসেছে — “১৮ পয়েন্ট অক্ষর, ২৯ পয়েন্ট লাইন” লেখা হতো 18/29. এখানেও এককহীন সংখ্যা দিন (অংশ ৫)।- font-family, বাধ্যতামূলক, সবার শেষে. তালিকাটি পুরো ঘোষণার শেষে থাকতে হবে। আকার আর family — এই দুটি ছাড়া
fontচলে না। - লুকানো ফাঁদ — রিসেট. shorthand যা লেখেননি, সেগুলোকে প্রাথমিক মানে ফিরিয়ে দেয়। আগে
line-height: 1.8দিয়ে পরেfont: 1rem sans-serifলিখলে line-height আবারnormalহয়ে যায়;font-size-adjust,font-variant-এর মতো কয়েকটি property-ও রিসেট হয়। তাই কোনো একটি অংশ আলাদা করে বদলাতে চাইলে সেই property-টি shorthand-এর পরে লিখুন।
কয়েকটি ভুল উদাহরণ চিনে রাখুন: font: bold 16px; (family নেই — অবৈধ), font: sans-serif 16px; (ক্রম উল্টো — অবৈধ), font: 16px/24px Arial; (বৈধ, কিন্তু line-height স্থির px — ভালো অভ্যাস নয়)।
৫ · line-height আর লাইনের দৈর্ঘ্য — চোখের যাত্রাপথ
line-height এক লাইন থেকে পরের লাইনের দূরত্ব ঠিক করে। পর্ব ১৪-এ দেখেছেন বাংলায় 1.6–1.8 আরামদায়ক, ইংরেজিতে প্রায়ই 1.4–1.6. কিন্তু কোন রূপে লিখবেন — 1.5, 1.5em, 150% নাকি 24px? চোখে একই দেখালেও উত্তরাধিকারে এদের আচরণ আলাদা। এককহীন সংখ্যা সন্তানের কাছে যায় গুণক হিসেবে — প্রতিটি সন্তান নিজের font-size দিয়ে গুণ করে। কিন্তু em, % বা px দিলে মা-element-এ হিসাব হয়ে যাওয়া সংখ্যাটি (যেমন 21px) সন্তানে যায় — সন্তানের লেখা যত বড়ই হোক:
div {
width: 250px;
font-family: system-ui, sans-serif;
font-size: 14px;
border: 1px dashed #999;
padding: 4px 8px;
margin-bottom: 10px;
}
.a { line-height: 1.5em; } /* সন্তান পায় 21px */
.b { line-height: 1.5; } /* সন্তান পায় "1.5 গুণ" */
.big { font-size: 28px; margin: 4px 0; }ওপরের বাক্সে শিরোনামের দুই লাইন একে অপরের গায়ে উঠে গেছে — 28px অক্ষরের জন্য লাইনের উচ্চতা মাত্র 21px, কারণ 1.5em মা-element-এই 21px-এ হিসাব হয়ে সন্তানে গেছে। নিচের বাক্সে একই শিরোনাম পরিষ্কার: এককহীন 1.5 সন্তানে গেছে গুণক হিসেবে, তাই 28 × 1.5 = 42px. চেষ্টা করুন: .a-তে 150% দিন — লাইনগুলো আগের মতোই গায়ে গায়ে উঠবে; তারপর .big-এর আকার 40px করুন — দুই বাক্সের পার্থক্য আরও স্পষ্ট হবে। এজন্যই নিয়ম: line-height সবসময় একক ছাড়া।
WCAG 2.2-এর ১.৪.১২ (Text Spacing): কোনো পাঠক নিজের স্টাইল বা এক্সটেনশন দিয়ে line-height অক্ষরের আকারের 1.5 গুণ, অনুচ্ছেদের পরের ফাঁক 2 গুণ, letter-spacing 0.12 গুণ আর word-spacing 0.16 গুণ করলেও লেখা কেটে যাওয়া বা একে অপরের ওপর উঠে যাওয়া চলবে না। স্থির height-এর বাক্সে লেখা রাখলে ঠিক এই নিয়মটাই ভাঙে — তাই লেখার বাক্সের উচ্চতা লেখাকেই ঠিক করতে দিন।
লাইনের দৈর্ঘ্য — measure
লাইন খুব লম্বা হলে চোখ এক লাইনের শেষ থেকে পরের লাইনের শুরু খুঁজে পেতে হিমশিম খায়, ভুল করে একই লাইন আবার পড়ে। খুব ছোট হলে চোখকে বারবার লাফাতে হয়, শব্দ ভেঙে ভেঙে যায়। এক লাইনে কতটি অক্ষর, তাকে ছাপাখানার ভাষায় বলে measure. Robert Bringhurst-এর বিখ্যাত বই The Elements of Typographic Style বলে, ইংরেজির মতো লেখায় ৪৫–৭৫টি অক্ষর সন্তোষজনক, আর প্রায় ৬৬টি আদর্শ। WCAG-এর ১.৪.৮ (AAA স্তর) বলে ৮০টির বেশি নয়।
CSS-এ এর জন্য চমৎকার একক আছে — ch: বর্তমান ফন্টের “0” অঙ্কটির প্রস্থ। max-width: 65ch মানে মোটামুটি ৬৫টি অক্ষরের জায়গা (আসল অক্ষর আকারে আলাদা, তাই হিসাবটা আনুমানিক)। বাংলায় যুক্তাক্ষর আর কার মিলে অক্ষর গোনা ইংরেজির মতো সরল নয়, তাই বাংলা লেখায় সংখ্যাটা চোখে দেখে ঠিক করুন — প্রিভিউতে কয়েকটি মান (ch বা em-এ) চেষ্টা করে যেটিতে পড়তে আরাম, সেটি নিন।
p {
font: 1rem/1.6 Georgia, serif;
border-left: 3px solid #93c5fd;
padding-left: 8px;
}
.narrow { max-width: 20ch; }
.ok { max-width: 65ch; }
p:not([lang]) { line-height: 1.75; } /* বাংলায় একটু বেশি */প্রথম অনুচ্ছেদ মাত্র 20ch — প্রতি লাইনে দুই-তিনটি শব্দ, চোখকে বারবার নিচে নামতে হয়। দ্বিতীয়টি 65ch — একটানা পড়তে আরাম। তৃতীয়টি একই প্রস্থে বাংলা। চেষ্টা করুন: .ok-এর মান 120ch করুন — প্রিভিউ যথেষ্ট চওড়া হলে লাইন পুরো পর্দা জুড়ে যাবে, আর পড়ার সময় লাইনের শুরুতে ফিরতে কষ্ট টের পাবেন। তারপর font-এর আকার 1.25rem করুন — খেয়াল করুন, ch ফন্টের সাথে মাপে, তাই লেখা বড় হলে বাক্সও চওড়া হয়, অক্ষরের সংখ্যা প্রায় একই থাকে।
৬ · লেখা সাজানো — align, spacing, transform, decoration আর shadow
text-align লাইনগুলোকে বাঁয়ে, ডানে, মাঝে বা দুই দিকে সমান (justify) করে। আধুনিক রূপ start আর end — লেখার দিক অনুযায়ী “শুরু” আর “শেষ”, তাই আরবি-উর্দুর মতো ডান থেকে বাঁয়ের পাতায় নিজে উল্টে যায়। লম্বা লেখায় বাঁয়ে সাজানো (start) সবচেয়ে নিরাপদ; মাঝে সাজানো শুধু ছোট শিরোনাম বা দুই-তিন লাইনে।
justify-এর ঝুঁকি: দুই দিক সমান রাখতে ব্রাউজার শব্দের মাঝের ফাঁক টেনে বড় করে। ছাপা বইয়ে কম্পোজিটর শব্দ ভেঙে হাইফেন দিয়ে আর অক্ষরের ফাঁক সূক্ষ্মভাবে বদলে এটা সামলান। ব্রাউজার সাধারণত শুধু শব্দের ফাঁক টানে, এক লাইন এক লাইন করে। ফলে সরু কলামে বিশাল ফাঁক তৈরি হয়, আর কয়েক লাইনের ফাঁক ওপর-নিচে মিলে লেখার ভেতর দিয়ে সাদা নদীর মতো রেখা দেখা দেয় — যাকে বলে river. ডিসলেক্সিয়া আছে এমন পাঠকদের জন্য এটি বিশেষ কষ্টের, তাই WCAG ১.৪.৮ (AAA) justify এড়াতে বলে। বাংলাদেশের ছাপা পত্রিকায় বাংলা justify খুব প্রচলিত, কিন্তু সেখানে দক্ষ হাতে সাজানো হয়; ওয়েবে বাংলায় ব্রাউজারের স্বয়ংক্রিয় হাইফেনও সাধারণত কাজ করে না, তাই ফোনের সরু পর্দায় বাংলা justify প্রায়ই ফাঁকে ভরা দেখায়। ওয়েবে বাঁয়ে সাজানোই ভালো।
| Property | কাজ | ব্যবহারিক পরামর্শ |
|---|---|---|
letter-spacing | অক্ষরের মাঝের ফাঁক | বড় হাতের অক্ষরে লেখা ছোট ইংরেজি লেবেলে সামান্য (0.05em–0.1em) ভালো দেখায়; মূল লেখায় নয়; বাংলায় নয় (অক্ষর আলগা হয়ে শব্দের গড়ন নষ্ট হয়, কোনো কোনো ফন্টে যুক্তাক্ষরও ভেঙে যেতে পারে)। মান em-এ দিন। |
word-spacing | শব্দের মাঝের ফাঁক | খুব কম দরকার হয়; পাঠক নিজে বাড়ালেও লেআউট যেন না ভাঙে (WCAG ১.৪.১২)। |
text-transform | uppercase, lowercase, capitalize | HTML-এ বড় হাতে টাইপ না করে CSS-এ দিন — মূল লেখা স্বাভাবিক থাকে। বাংলায় বড়-ছোট হাত নেই, তাই কোনো প্রভাব নেই। |
text-indent | অনুচ্ছেদের প্রথম লাইনের শুরুতে ফাঁক | বইয়ের ধাঁচ: p + p { text-indent: 2em; } আর অনুচ্ছেদের মাঝে margin নয় — দুটোর যেকোনো একটি। |
text-decoration | নিচে দাগ, ওপরে দাগ, কাটা দাগ | লিংকের underline রাখুন; চাইলে text-decoration-thickness, text-underline-offset, text-decoration-color দিয়ে সুন্দর করুন (সবই Baseline Widely available). |
text-shadow | লেখার ছায়া | ছবির ওপরের লেখা পড়া সহজ করতে হালকা ছায়া কাজে লাগে; মূল লেখায় ঝাপসা দেখায়। ছায়া দিয়ে কম contrast ঢাকা যায় না। |
লিংকের underline নিয়ে একটি কথা আলাদা করে বলা দরকার। অনেক ডিজাইনে a { text-decoration: none; } লিখে শুধু রং দিয়ে লিংক চেনানো হয়। কিন্তু রং-অন্ধ পাঠক বা রোদের নিচে ফোনে পড়া কেউ লিংকটি আলাদা করতে পারেন না। WCAG ১.৪.১ (Use of Color) বলে, শুধু রং দিয়ে তথ্য দেওয়া চলবে না। লেখার ভেতরের লিংকে underline রাখাই সবচেয়ে সহজ সমাধান — আর আধুনিক CSS দিয়ে underline-কেও সুন্দর করা যায়:
body { font: 1.125rem/1.7 system-ui, sans-serif; }
a {
color: #1d4ed8;
text-decoration-thickness: 2px;
text-underline-offset: 4px;
text-decoration-color: #93c5fd;
}
a:hover { text-decoration-color: currentColor; }
.label { text-transform: uppercase; letter-spacing: 0.08em;
font-size: 0.8rem; font-weight: 600; color: #555; margin: 0; }
.hero { background: linear-gradient(135deg, #0ea5e9, #f59e0b); padding: 16px; }
.shadow { color: #fff; font-size: 1.6rem; margin: 0;
text-shadow: 0 1px 3px rgb(0 0 0 / 0.5); }ওপরে ইংরেজি লেবেল বড় হাতের অক্ষরে, অক্ষরের মাঝে একটু ফাঁক — HTML-এ কিন্তু ছোট হাতে লেখা। ঠিক নিচে একই নিয়মের বাংলা লেবেল: uppercase-এর কোনো প্রভাব নেই, শুধু ফাঁক বেড়েছে, আর অক্ষরগুলো আলগা হয়ে শব্দের স্বাভাবিক গড়ন হারিয়েছে। লিংক দুটির underline মোটা, লেখা থেকে একটু নিচে, হালকা নীল — মাউস রাখলে গাঢ় হয়; underline বাংলার নিচের চিহ্ন (ু, ূ) কেটে যায় না, কারণ offset দেওয়া আছে। শেষে gradient-এর ওপর সাদা লেখা, ছায়ার কারণে পড়া সহজ। চেষ্টা করুন: text-underline-offset মুছে দিন — underline বাংলার নিচের অংশের কাছে চলে আসবে; তারপর text-shadow লাইনটি মুছে দেখুন gradient-এর হলুদ অংশে লেখা কতটা হারিয়ে যায়।
৭ · লাইন কোথায় ভাঙবে — white-space, text-wrap, hyphens আর লম্বা URL
ব্রাউজার নিজে ঠিক করে কোথায় লাইন ভাঙবে — সাধারণত শব্দের মাঝের ফাঁকে। কিছু জায়গায় আপনি এই সিদ্ধান্তে হাত দিতে চাইবেন।
white-space— HTML-এ একাধিক space আর নতুন লাইন এক হয়ে যায় (পর্ব ০৩-এর whitespace collapsing).nowrapলাইন ভাঙতে দেয় না (যেমন “৳ ১,২৫০” বা একটি ফোন নম্বর যেন দুই লাইনে না ভাঙে);preলেখা যেমন আছে তেমন রাখে;pre-wrapspace রাখে কিন্তু দরকারে লাইন ভাঙে (কবিতা, চ্যাটের বার্তা);pre-lineশুধু নতুন লাইন রাখে।text-wrap: balance— শিরোনামের লাইনগুলো সমান দৈর্ঘ্যের করে, যাতে শেষ লাইনে একটি শব্দ একা ঝুলে না থাকে। খরচ বাঁচাতে ব্রাউজার কয়েক লাইনের বেশি লেখায় এটি করে না, তাই শুধু শিরোনাম আর ছোট লেখায় দিন। এটি Baseline Newly available (২০২৪ থেকে সব প্রধান ব্রাউজারে)।text-wrap: pretty— অনুচ্ছেদের শেষ লাইনে একা একটি শব্দ (orphan) এড়ায়, লাইন ভাঙার সময় পুরো অনুচ্ছেদের কিছুটা বিবেচনা করে। এটি সাম্প্রতিক ফিচার, এখনো Baseline নয় — কয়েকটি ব্রাউজারে আছে, বাকিগুলোতে আসছে; Can I use দেখে নিন। না চললে ক্ষতি নেই, সাধারণ ভাঙা হয় — তাই নির্ভয়ে লেখা যায় (progressive enhancement).hyphens: auto— দরকারে শব্দ ভেঙে হাইফেন দেয় (inter-national). কিন্তু ব্রাউজারকে ভাষা জানতে হবে —langattribute ছাড়া কাজই করে না, আর সেই ভাষার হাইফেন-অভিধান ব্রাউজারে থাকতে হবে। ইংরেজিতে বেশিরভাগ ব্রাউজার পারে, তবে যন্ত্র আর ব্রাউজারভেদে পার্থক্য আছে; বাংলায় সাধারণত পারে না।overflow-wrap: anywhere— এমন লম্বা “শব্দ”, যার মাঝে কোনো ফাঁক নেই (URL, ইমেইল, লম্বা হ্যাশট্যাগ, লেনদেনের TrxID), সেটি বাক্স ছাপিয়ে বেরিয়ে যায় আর ফোনে পুরো পাতা পাশে সরে (horizontal scroll). এই property বলে, “দরকার হলে শব্দের মাঝেও ভাঙো”। পুরোনোbreak-wordমানও আছে; পার্থক্য সূক্ষ্ম —anywhereflex বা grid-এ বাক্সের ন্যূনতম প্রস্থের হিসাবেও ভাঙার সুযোগ ধরে।word-break: break-allসব শব্দকেই যেকোনো অক্ষরে ভাঙে — সাধারণ লেখায় অসুন্দর; আরword-break: break-wordপুরোনো, বাতিলের পথে।
.card {
width: 220px;
border: 1px solid #ccc;
padding: 8px 10px;
font: 1rem/1.6 system-ui, sans-serif;
}
.bal { text-wrap: balance; font-size: 1.2rem; line-height: 1.35; margin: 0 0 8px; }
.url { overflow-wrap: anywhere; color: #1d4ed8; font-size: 0.85rem; }
.nw { white-space: nowrap; }
.hy { hyphens: auto; max-width: 8em; }সরু কার্ডে শিরোনামের লাইনগুলো প্রায় সমান দৈর্ঘ্যের — শেষ লাইনে একা “প্রকাশ” ঝুলে নেই। লম্বা URL-টি কার্ডের ভেতরেই কয়েক লাইনে ভেঙেছে। “৳ ১,২৫০” কখনো দুই লাইনে ভাঙবে না। শেষ ইংরেজি বাক্যটি 8em-এ সীমিত। আপনার ব্রাউজারে ইংরেজির হাইফেন-অভিধান থাকলে লম্বা শব্দগুলো ভেঙে “-” বসবে — আর তা সম্ভব হচ্ছে lang="en"-এর জন্য। অভিধান না থাকলে (Windows-এর কিছু ব্রাউজারে এমন হয়) internationalization আস্ত পরের লাইনে যায়, 8em-এর সীমা ছাড়িয়েও — hyphens যে অভিধাননির্ভর, তা চোখেই দেখলেন। চেষ্টা করুন: .url লাইনটি মুছে দিন — URL কার্ড ছাপিয়ে ডানে বেরিয়ে যাবে। text-wrap: balance মুছলে শিরোনামের শেষ লাইনটি হয়তো ছোট হয়ে যাবে। হাইফেন দেখা গেলে শেষ অনুচ্ছেদ থেকে lang="en" মুছে দেখুন — হাইফেন চলে যাবে, কারণ প্রিভিউর পাতা বাংলা ঘোষিত।
আরও গভীরে: লাইন কোথায় ভাঙা যায়, তা ব্রাউজার নিজে বানায় না — Unicode-এর UAX #14 (Unicode Line Breaking Algorithm) প্রতিটি অক্ষরের জন্য ভাঙার নিয়ম দেয়: space-এর পরে ভাঙা যায়, “–”-এর আশপাশে নির্দিষ্ট নিয়ম, চীনা-জাপানিতে প্রায় প্রতিটি অক্ষরের পরে। বাংলায় ভাঙা হয় মূলত space-এ, আর কখনোই একটি যুক্তাক্ষর বা কার-চিহ্নের মাঝে নয় (পর্ব ১৪-এর অক্ষরগুচ্ছ)। ব্রাউজার সাধারণত “লোভী” (greedy) পদ্ধতিতে ভাঙে — যতটা ধরে ততটা লাইনে বসায়, পরের লাইনের কথা না ভেবে; text-wrap: pretty এর বদলে কয়েক লাইন একসাথে বিবেচনা করে। CSS Text Level 4-এ white-space এখন আসলে দুটি property-র shorthand — white-space-collapse আর text-wrap-mode; আর text-wrap নিজেও text-wrap-mode ও text-wrap-style-এর shorthand.
৮ · ওয়েব ফন্ট — @font-face, woff2 আর font-display
পাঠকের যন্ত্রে নেই এমন ফন্ট দেখাতে চাইলে ফন্টের ফাইলটি পাতার সাথে নামাতে হয় — একে বলে web font. CSS-এ এর ঘোষণা @font-face: আপনি একটি নাম দেন, আর বলে দেন ফাইল কোথায়। নিজের সার্ভারে রাখা ফন্ট এভাবে ঘোষণা করা হয়:
/* নিজের সার্ভারে রাখা ফন্ট (self-hosting) */
@font-face {
font-family: "Hind Siliguri"; /* CSS-এ এই নামে ডাকবেন */
src: url("/fonts/hind-siliguri-400.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap; /* লেখা কখনো অদৃশ্য নয় */
}
@font-face {
font-family: "Hind Siliguri"; /* একই নাম, ভিন্ন ওজন */
src: url("/fonts/hind-siliguri-600.woff2") format("woff2");
font-weight: 600;
font-display: swap;
}
body { font-family: "Hind Siliguri", system-ui, sans-serif; }কয়েকটি বিষয় খেয়াল করুন। এক, একই font-family নামে কয়েকটি @font-face — প্রতিটি একটি ওজন বা style; ব্রাউজার font-weight: 600 দেখে ঠিক ফাইলটি বাছে। দুই, শুধু WOFF2 — এটি ওয়েবের জন্য বানানো সংকুচিত ফরম্যাট (ভেতরে Brotli সংকোচন), সব আধুনিক ব্রাউজারে চলে। পুরোনো টিউটোরিয়াল আর AI প্রায়ই .eot, .svg, .ttf, .woff মিলিয়ে লম্বা “bulletproof” তালিকা দেয় — সেটা Internet Explorer আর পুরোনো iPhone-এর যুগের অভ্যাস, আজ দরকার নেই। তিন, ব্রাউজার ফন্ট ফাইল নামায় অলসভাবে — শুধু ঘোষণা দেখে নয়, পাতায় সত্যিই সেই ফন্টে লেখা কোনো অক্ষর থাকলে তবেই।
ফন্ট আসার আগে কী দেখাবে — FOIT, FOUT আর font-display
ফন্ট নামতে সময় লাগে — ধীর মোবাইল ডেটায় কয়েক সেকেন্ডও। এই সময় লেখার কী হবে? দুই রকম অভিজ্ঞতা আছে: লেখা লুকিয়ে রাখা, যাকে বলে FOIT (Flash of Invisible Text), আর আগে বিকল্প ফন্টে দেখিয়ে পরে বদলানো, যাকে বলে FOUT (Flash of Unstyled Text). কোনটা হবে, ঠিক করে font-display. সময়রেখা ধরে দেখুন:
- লেখা পাওয়া গেল
font-family: "Hind…"ফন্ট লাগবে - ডাউনলোড শুরু
.woff2সময় শুরু: 0 - block period
অদৃশ্য লেখাFOIT - swap period
fallback ফন্টFOUT - ফন্ট এল
বদল + reflowবা আর বদল নয়
- দরকার টের পাওয়া. ব্রাউজার HTML আর CSS পড়ে লেখা সাজাতে গিয়ে দেখল, এই অনুচ্ছেদের ফন্ট একটি ওয়েব ফন্ট, যা এখনো নামানো হয়নি। ফন্টের অনুরোধ তাই সাধারণত বেশ দেরিতে শুরু হয় — CSS নামার আর পড়ার পরে।
<link rel="preload" as="font" type="font/woff2" crossorigin>দিয়ে আগেভাগে নামানো শুরু করা যায় (খুব জরুরি এক-দুটি ফাইলের জন্যই)। - ডাউনলোড আর ঘড়ি. অনুরোধ যাওয়ার মুহূর্ত থেকে ব্রাউজার একটি ঘড়ি চালায়।
font-display-এর পাঁচটি মান —auto,block,swap,fallback,optional— আসলে এই ঘড়ির দুটি সময়সীমা ঠিক করে। - block period — অদৃশ্য লেখা. এই সময়ে লেখার জায়গা রাখা হয়, কিন্তু লেখা অদৃশ্য (FOIT).
block-এ এটি প্রায় ৩ সেকেন্ড — ধীর নেটে পাঠক ফাঁকা পাতা দেখেন।swap,fallback,optional-এ এটি খুব ছোট, চোখে প্রায় পড়ে না। (সময়গুলো স্পেসিফিকেশনের সুপারিশ; ব্রাউজারভেদে একটু আলাদা হতে পারে।) - swap period — বিকল্প ফন্টে লেখা. এবার লেখা fallback ফন্টে দেখায় (FOUT), পাঠক পড়া শুরু করতে পারেন।
swap-এ এই সময় অসীম — যখনই ফন্ট আসুক, বদলে যাবে।fallback-এ প্রায় ৩ সেকেন্ড, তারপর হাল ছেড়ে দেয়।optional-এ swap period শূন্য — ফন্ট তখনই না থাকলে এই পাতায় আর বদল নয়। - ফন্ট এল. আসল ফন্টে বদলালে অক্ষরের প্রস্থ আর উচ্চতা বদলায়, লেখা নতুন করে সাজে, নিচের সব কিছু একটু সরে — এটা layout shift, যা CLS-এ যোগ হয় (পর্ব ৪৯)।
optionalএই লাফ এড়ায়, ফন্ট ক্যাশে রেখে দেয় পরের পাতার জন্য। বেশিরভাগ লেখার সাইটেswapভালো আপস; গতি সবচেয়ে জরুরি হলেoptional.
লাফ কমানোর আরেকটি উপায়: fallback ফন্টকে আসল ফন্টের মাপের কাছাকাছি আনা। @font-face-এ size-adjust, ascent-override, descent-override নামের descriptor দিয়ে একটি স্থানীয় ফন্ট (যেমন src: local("Arial")) একটু বড়-ছোট করে নেওয়া যায়, যাতে বদলের সময় লাইনগুলো প্রায় একই জায়গায় থাকে। সব descriptor সব ব্রাউজারে সমানভাবে কাজ করে না, তবে না চললে ক্ষতি নেই।
Google Fonts নাকি নিজের সার্ভার?
Google Fonts (২০১০ সালে শুরু) সবচেয়ে সহজ পথ: সাইট থেকে ফন্ট বেছে একটি <link> কপি করে head-এ বসান, সাথে preconnect. লিংকের URL-এ display=swap রাখুন আর শুধু যে ওজনগুলো লাগবে সেগুলো নিন (wght@400;600) — প্রতিটি ওজন আলাদা ফাইল। পর্ব ১৪-এ দেখেছেন, Google ফাইলগুলো ভাগ করে আর unicode-range দিয়ে শুধু দরকারি অংশ নামায়।
Google Fonts-এর লিংক
পাঁচ মিনিটে শেষ; ফাইল ভাগ, সংকোচন, ব্রাউজার অনুযায়ী ফরম্যাট — Google সামলায়। কিন্তু দুটি আলাদা ডোমেইনে সংযোগ লাগে, আর পাঠকের IP ঠিকানা Google-এর সার্ভারে যায় — ইউরোপের গোপনীয়তা আইনে এটা নিয়ে মামলাও হয়েছে।
সহজSelf-hosting
নিজের সার্ভারে woff2 ফাইল রেখে @font-face. একই ডোমেইন, তৃতীয় পক্ষ নেই, ক্যাশের নিয়ম আপনার হাতে। “সব সাইট একই Google ফন্ট শেয়ার করে ক্যাশ থেকে পায়” — এই পুরোনো সুবিধা ব্রাউজারের cache partitioning-এর পর আর নেই।
নিজের সার্ভারে রাখার আগে দুটি কাজ: ফন্টের লাইসেন্স দেখুন (Google Fonts-এর ফন্টগুলো সাধারণত SIL Open Font License-এ, নিজের সার্ভারে রাখা যায়), আর বাংলা ফন্ট হলে বাংলা ও ইংরেজি অক্ষর দুটোই আছে এমন woff2 নিন।
৯ · Variable font আর font-size-adjust — এক ফাইলে অনেক ফন্ট
সাধারণ ফন্টে প্রতিটি ওজন আর style আলাদা ফাইল: Regular, Bold, Light, Italic… চারটি ওজন মানে চারটি ডাউনলোড। ২০১৬ সালে OpenType 1.8 স্পেসিফিকেশনে Apple, Google, Microsoft আর Adobe একসাথে variable font আনে: একটি ফাইলের ভেতরে নকশার কয়েকটি “অক্ষ” (axis), আর অক্ষ ধরে যেকোনো মাঝামাঝি মান। নিবন্ধিত পাঁচটি অক্ষ — wght (ওজন), wdth (প্রস্থ), ital (italic), slnt (হেলানো), opsz (optical size — ছোট লেখায় একটু মোটা ও খোলা, বড় শিরোনামে সূক্ষ্ম)। ফন্ট-নির্মাতা নিজের অক্ষও বানাতে পারেন, যার নাম বড় হাতের অক্ষরে (যেমন GRAD).
@font-face {
font-family: "Anek Bangla";
src: url("/fonts/anek-bangla-variable.woff2") format("woff2");
font-weight: 100 800; /* একটি ফাইল, পুরো পরিসর */
font-display: swap;
}
h1 { font-weight: 750; } /* মাঝের যেকোনো মান */
p { font-weight: 430; }
.ad { font-variation-settings: "wdth" 80; } /* নিচু স্তরের উপায় */অক্ষ বদলানোর দুটি উপায়। ভালো উপায় — পরিচিত property: font-weight (wght), font-stretch (wdth), font-style (ital/slnt), font-optical-sizing: auto (opsz, ডিফল্টেই চালু)। নিচু স্তরের উপায় — font-variation-settings, যেখানে চার অক্ষরের ট্যাগ আর সংখ্যা সরাসরি লেখেন। এটি শুধু তখন লিখুন যখন কোনো সাধারণ property নেই (নিজস্ব অক্ষ)। কারণ এর একটি ফাঁদ আছে: এটি সব অক্ষ একসাথে একটি মান হিসেবে ধরে, তাই কোনো সন্তান element-এ শুধু একটি অক্ষ বদলাতে লিখলে মা-element-এর অন্য অক্ষগুলো হারিয়ে যায়। variable font-এর মূল সুবিধাগুলো (@font-face-এ ওজনের পরিসর, font-variation-settings) Baseline Widely available.
হিসাবটা মাথায় রাখুন: একটি variable font ফাইল একটি সাধারণ ফাইলের চেয়ে বড়, কিন্তু তিন-চারটি ওজনের মোট ফাইলের চেয়ে প্রায়ই ছোট — আর অনুরোধ একটি। শুধু একটি ওজন লাগলে সাধারণ ফাইলই হালকা।
font-size-adjust — দুই ফন্টের চোখে-দেখা আকার মেলানো
একই font-size-এ সব ফন্ট সমান বড় দেখায় না। কারণ font-size মাপে অক্ষরের পুরো “বাক্স”, আর চোখে আকার বোঝায় মূলত ছোট হাতের অক্ষরের উচ্চতা — x অক্ষরটির উচ্চতা, যাকে বলে x-height. Verdana-র x-height বড়, Times New Roman-এর ছোট। ফলে ওয়েব ফন্ট না আসা পর্যন্ত fallback ফন্টে লেখা হঠাৎ ছোট বা বড় দেখায়, বা এক বাক্যে দুই ফন্ট মেলালে অমিল চোখে পড়ে। font-size-adjust বলে, “x-height হবে font-size-এর এত ভাগ” — ব্রাউজার প্রতিটি ফন্টের আকার সেই অনুযায়ী বদলে নেয়। এটি Baseline Newly available (সব প্রধান ব্রাউজারে সম্প্রতি এসেছে); না চললে শুধু আকার একটু অমিল থাকে।
<style>
p { font-size: 30px; margin: 4px 0; }
.t { font-family: "Times New Roman", serif; }
.v { font-family: Verdana, sans-serif; }
.adj { font-size-adjust: 0.5; }
small { font: 12px monospace; color: #666; }
</style>
<p><span class="t">xhgy Times</span> <span class="v">xhgy Verdana</span>
<small>দুটিই 30px</small></p>
<p class="adj"><span class="t">xhgy Times</span> <span class="v">xhgy Verdana</span>
<small>font-size-adjust: 0.5</small></p>প্রথম লাইনে দুটি অংশই 30px, অথচ Verdana-র ছোট হাতের অক্ষর (x, h, g, y-এর মূল অংশ) Times-এর চেয়ে স্পষ্ট বড়। দ্বিতীয় লাইনে font-size-adjust: 0.5 দুই ফন্টকেই এমনভাবে বড়-ছোট করেছে যে x-height হয় 15px — এবার ছোট হাতের অক্ষর সমান উঁচু, Times একটু বড় আর Verdana একটু ছোট হয়েছে। (Times আর Verdana Windows ও Mac-এ সাধারণত থাকে; না থাকলে অন্য ফন্টে একই ধারণা দেখবেন।) চেষ্টা করুন: 0.5-কে 0.6 করুন — দুটিই বড় হবে, সমান থেকেই। তারপর from-font লিখে দেখুন — তখন প্রথম পাওয়া ফন্টের নিজস্ব অনুপাতটাই মানদণ্ড হয় (এই মানটি সব ব্রাউজারে না-ও চলতে পারে)।
১০ · AI-এর যুগে — টাইপোগ্রাফির CSS AI-কে দিয়ে লেখালে কী দেখবেন
AI টুল চোখের পলকে সুন্দর দেখতে CSS দেয়। কিন্তু তাদের শেখার উপাদানে বহু বছরের পুরোনো ব্লগ আর টেমপ্লেট, তাই পুরোনো অভ্যাস প্রায়ই ফিরে আসে — আর টাইপোগ্রাফির ভুল সাধারণত চোখে পড়ে না, কারণ আপনার কম্পিউটারে, আপনার দ্রুত ইন্টারনেটে, আপনার ডিফল্ট লেখার আকারে সব ঠিক দেখায়:
| AI-এর ভুল | কেন সমস্যা | ঠিক উপায় |
|---|---|---|
সব আকার px-এ, line-height: 24px | পাঠকের সেট করা লেখার আকার মানা হয় না; বড় লেখায় লাইন চাপা | আকার rem-এ, line-height এককহীন |
| Google Fonts-এ ৬–৯টি ওজন একসাথে | অপ্রয়োজনীয় ডাউনলোড, ধীর প্রথম লোড | ২–৩টি ওজন, বা একটি variable font |
@font-face-এ eot/svg/ttf তালিকা, font-display নেই | পুরোনো যুগের অভ্যাস; ধীর নেটে অদৃশ্য লেখা | শুধু woff2, font-display: swap |
a { text-decoration: none; } | লিংক শুধু রঙে চেনা যায় — WCAG ১.৪.১ | লেখার ভেতরের লিংকে underline রাখুন |
মূল লেখা font-weight: 300, হালকা ধূসর | পাতলা অক্ষর + কম contrast = অনেকের কাছে অপাঠ্য | 400 বা বেশি, যথেষ্ট contrast |
সব অনুচ্ছেদে text-align: justify | ফোনে বড় ফাঁক আর river, বিশেষ করে বাংলায় | text-align: start |
word-break: break-all বা পুরোনো break-word | সাধারণ শব্দও মাঝখানে ভাঙে; পুরোনো মান বাতিলের পথে | শুধু দরকারি জায়গায় overflow-wrap: anywhere |
-webkit-font-smoothing সর্বত্র | শুধু Mac-এ কাজ করে, অ-মানক; অন্য যন্ত্রে প্রভাব নেই | দরকার নেই; মানক CSS-এ মন দিন |
শর্তগুলো আগেই লিখে দিলে প্রথম উত্তরেই আধুনিক CSS পাবেন। শেষ লাইনে AI-কে নিজের অনিশ্চয়তা জানাতে বলা হয়েছে — নতুন CSS ফিচারের ব্রাউজার-সমর্থন নিয়ে AI প্রায়ই ভুল বলে।
AI-এর দেওয়া টাইপোগ্রাফি হাতে পেলে — যাচাইয়ের চেকলিস্ট
পরীক্ষা ও ইন্টারভিউতে — বিশ্ববিদ্যালয়, চাকরি বা ফ্রন্ট-এন্ড ইন্টারভিউর পরীক্ষায় এ ধরনের প্রশ্ন প্রায়ই আসে:
- line-height এককহীন দেওয়া ভালো কেন? — এককহীন সংখ্যা গুণক হিসেবে উত্তরাধিকারে যায়, প্রতিটি সন্তান নিজের font-size দিয়ে হিসাব করে; em/px দিলে মা-element-এর হিসাব করা মান যায়।
- font-family-র শেষে generic family কেন? — তালিকার কোনো ফন্ট না পেলেও ব্রাউজার যেন অন্তত সঠিক ধরনের (যেমন sans-serif) ফন্ট দেয়।
- rem আর em-এর পার্থক্য? — rem মূল html-এর font-size-এর গুণিতক, em মা-element-এর (font-size-এ) বা নিজের font-size-এর (অন্য property-তে); em ভেতরে ভেতরে গুণ জমায়।
- FOIT আর FOUT কী, font-display: swap কী করে? — FOIT-এ ফন্ট আসা পর্যন্ত লেখা অদৃশ্য, FOUT-এ আগে বিকল্প ফন্টে দেখায়; swap খুব ছোট block period দিয়ে FOUT বেছে নেয়।
fontshorthand-এ কোন দুটি অংশ বাধ্যতামূলক? — font-size আর font-family, এই ক্রমে শেষের দিকে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলো আপনাকে property-মুখস্থকারী থেকে পাঠক-সচেতন ডিজাইনার বানাবে।
প্র ০১“Web design is 95% typography” — কথাটা কেন বলা হয়েছিল, আর ওয়েবে ফন্টের ইতিহাস এই দাবিকে কীভাবে ব্যাখ্যা করে?
২০০৬ সালে Oliver Reichenstein (iA নামের ডিজাইন প্রতিষ্ঠানের প্রতিষ্ঠাতা) এই শিরোনামে একটি প্রবন্ধ লেখেন। তাঁর যুক্তি সরল: ওয়েবের তথ্যের প্রায় সবটাই লেখা, তাই লেখাকে পাঠযোগ্য করাই ওয়েব ডিজাইনারের মূল কাজ — ছবি, রং আর সাজসজ্জা তার পরে। ৯৫ সংখ্যাটা কোনো জরিপের ফল নয়, জোর দেওয়ার ভঙ্গি।
দাবিটা সেই সময়ে বিপ্লবী শোনাত, কারণ তখনকার ওয়েবে টাইপোগ্রাফি নিয়ন্ত্রণের সুযোগই ছিল কম। ১৯৯০-এর দশকে ডিজাইনাররা শুধু সেই ফন্টগুলো ব্যবহার করতে পারতেন, যা প্রায় সবার কম্পিউটারে আছে — তথাকথিত “web-safe” ফন্ট। ১৯৯৬ সালে Microsoft “Core fonts for the Web” নামে বিনামূল্যে কয়েকটি ফন্ট ছড়িয়ে দেয়; তার মধ্যে Georgia আর Verdana — দুটিই Matthew Carter-এর নকশা — বিশেষভাবে কম রেজোলিউশনের পর্দার জন্য বানানো, বড় x-height আর খোলা আকারে। সুন্দর ফন্ট চাইলে মানুষ লেখাকে ছবি বানিয়ে দিত, যা সার্চ ইঞ্জিন আর screen reader পড়তে পারত না। CSS2-তে @font-face-এর ধারণা ছিল, কিন্তু ফরম্যাট আর লাইসেন্সের জটিলতায় বহু বছর কার্যত অচল ছিল; ২০০৮–২০১০-এর দিকে ব্রাউজারগুলো এটি ভালোভাবে চালু করে, তারপর আসে WOFF ফরম্যাট আর ২০১০ সালে Google Fonts.
আজ আমাদের হাতে অসংখ্য ফন্ট, variable font, text-wrap, ch — কিন্তু Reichenstein-এর মূল কথা আরও বেশি প্রাসঙ্গিক। এখন মানুষ ফোনের ছোট পর্দায়, চলন্ত বাসে, রোদের নিচে পড়েন। একটি সাইটের ডিজাইন যতই আকর্ষণীয় হোক, যদি মূল লেখা ১৩px হালকা ধূসর, পাতলা ফন্টে হয়, পাঠক চলে যাবেন।
মূল উপলব্ধি: ওয়েবের মূল পণ্য লেখা, আর টাইপোগ্রাফি সেই পণ্যের মোড়ক নয়, ব্যবহারযোগ্যতা। ফন্টের স্বাধীনতা পেয়েছি সম্প্রতি; পড়ার আরামের নিয়ম কিন্তু ছাপাখানার কয়েকশো বছরের পুরোনো।
প্র ০২ছাপা বই আর পত্রিকায় justify এত সুন্দর দেখায়, অথচ ওয়েবে কেন ঝুঁকিপূর্ণ? ব্রাউজার আর ছাপার সফটওয়্যারের লাইন ভাঙার পদ্ধতিতে পার্থক্য কোথায়?
justify করা লেখায় প্রতিটি লাইন দুই দিকেই সমান — কিন্তু শব্দগুলো তো সমান দৈর্ঘ্যের নয়, তাই কোথাও না কোথাও বাড়তি জায়গা ভাগ করে দিতে হয়। ছাপার জগতে এই সমস্যা সমাধানের কাজকে বলে H&J — hyphenation and justification. দক্ষ কম্পোজিটর তিনটি হাতিয়ার একসাথে ব্যবহার করেন: শব্দ ভেঙে হাইফেন, শব্দের ফাঁকের সূক্ষ্ম বদল, আর কখনো অক্ষরের ফাঁক বা আকারের প্রায় অদৃশ্য বদল।
কম্পিউটারে এর সবচেয়ে বিখ্যাত সমাধান দেন Donald Knuth আর Michael Plass, ১৯৮১ সালের একটি গবেষণাপত্রে — TeX টাইপসেটিং ব্যবস্থার অংশ হিসেবে। তাঁদের পদ্ধতি পুরো অনুচ্ছেদকে একসাথে বিবেচনা করে: সম্ভাব্য সব ভাঙার জায়গা থেকে এমন সমন্বয় খোঁজে, যাতে মোট “খারাপ লাগা” সবচেয়ে কম হয়। প্রথম লাইনে একটি শব্দ কম নিলে হয়তো পরের পাঁচ লাইন অনেক সুন্দর হয়।
ব্রাউজারের চ্যালেঞ্জ আলাদা: পর্দার প্রস্থ যেকোনো হতে পারে, লেখা বদলায়, আর প্রতিবার আকার বদলালে মিলিসেকেন্ডে আবার সাজাতে হয়। তাই ব্রাউজার ঐতিহ্যগতভাবে “লোভী” পদ্ধতি নেয় — লাইন যতটা ধরে ততটা ভরে, পরের লাইন না ভেবে। justify-তে তখন শুধু শব্দের ফাঁক টানা হয়, আর হাইফেন সাধারণত বন্ধ থাকে। ফলাফল: সরু কলামে বিশাল ফাঁক, আর ওপর-নিচের ফাঁক মিলে river. এই অসম ফাঁক ডিসলেক্সিয়া আছে এমন পাঠকদের পড়ার ছন্দ ভেঙে দেয়, তাই WCAG ১.৪.৮ (AAA) justify না করার কথা বলে।
বাংলায় সমস্যা আরও বেশি। বাংলা পত্রিকায় justify প্রচলিত, কিন্তু ব্রাউজারে বাংলার স্বয়ংক্রিয় হাইফেন সাধারণত নেই, আর বাংলা শব্দ প্রায়ই লম্বা (“পরিসংখ্যান”, “বিশ্ববিদ্যালয়”)। text-wrap: pretty ব্রাউজারে অনুচ্ছেদ-ভিত্তিক ভাবনার কিছুটা আনছে, কিন্তু তা মূলত শেষ লাইনের একা শব্দ এড়াতে।
মূল উপলব্ধি: justify সুন্দর হয় তখনই, যখন পেছনে হাইফেন আর অনুচ্ছেদ-ভিত্তিক হিসাব থাকে। ব্রাউজারে সেই হাতিয়ার সীমিত — তাই ওয়েবে বাঁয়ে সাজানো লেখাই নিরাপদ, বিশেষ করে বাংলায় আর ফোনে।
প্র ০৩অদৃশ্য লেখা (FOIT) নাকি লাফ দেওয়া লেখা (FOUT) — কোনটা কম খারাপ? font-display-এর জন্ম কেন হলো, আর বাংলা সাইটে কোন মান বেছে নেবেন?
ওয়েব ফন্ট জনপ্রিয় হওয়ার শুরুতে ব্রাউজারগুলো দুই পথে হাঁটল। কিছু ব্রাউজার ফন্ট না আসা পর্যন্ত লেখা লুকিয়ে রাখত, যাতে পাঠক “ভুল” ফন্ট না দেখেন — ডিজাইনারদের পছন্দ। কিছু ব্রাউজার আগে সিস্টেম ফন্টে দেখিয়ে পরে বদলাত — পাঠকের জন্য ভালো, কিন্তু লেখা হঠাৎ লাফায়। পরে বেশিরভাগ ব্রাউজার একটি মাঝামাঝি নিয়মে আসে: প্রায় ৩ সেকেন্ড লুকিয়ে রাখা, তারপর বিকল্প ফন্ট। কিন্তু সিদ্ধান্তটা ছিল ব্রাউজারের, সাইটের নয়; আর একেক ব্রাউজারে একেক রকম।
ধীর নেটওয়ার্কে ৩ সেকেন্ড ফাঁকা পাতা মানে অনেক পাঠক চলে যান। গ্রামের দুর্বল মোবাইল সংযোগে, বা লোডশেডিংয়ের পর ভিড় করা নেটওয়ার্কে, একটি বাংলা ফন্ট ফাইল (শত শত যুক্তাক্ষরের glyph থাকায় ইংরেজির চেয়ে ভারী) নামতে সত্যিই সময় লাগে। একজন পরীক্ষার্থী ফল দেখতে ঢুকে ফাঁকা পর্দা দেখছেন — অথচ HTML-এ লেখা অনেক আগেই এসে গেছে, শুধু ফন্টের অপেক্ষা!
এই নিয়ন্ত্রণ সাইটের হাতে দিতে CSS Fonts Level 4-এ আসে font-display. এর পেছনের ধারণা হলো দুটি সময়সীমা — block period আর swap period — যা আপনি স্টেপারে দেখেছেন। এখন উত্তরটা নির্ভর করে আপনার সাইটের প্রকৃতির ওপর। খবর, ব্লগ, সরকারি সেবা — যেখানে লেখা পড়াই উদ্দেশ্য — সেখানে swap: লেখা সঙ্গে সঙ্গে দেখা যায়, পরে সুন্দর হয়। গতি আর স্থিরতা সবচেয়ে জরুরি হলে optional: প্রথমবার হয়তো সিস্টেম ফন্টেই পাতা, কিন্তু কোনো লাফ নেই, পরের পাতা থেকে আসল ফন্ট। লোগো বা আইকন ফন্ট, যেখানে বিকল্প ফন্টে দেখালে অর্থই বদলে যায়, সেখানে block যুক্তিসঙ্গত — যদিও আইকনের জন্য আজ SVG ভালো (পর্ব ৪৪)।
মূল উপলব্ধি: পাঠকের কাছে “ভুল ফন্টে লেখা” প্রায় সবসময় “কোনো লেখা নেই”-এর চেয়ে ভালো। font-display সেই সিদ্ধান্ত ব্রাউজারের কাছ থেকে আপনার হাতে দিয়েছে — দায়িত্বও এখন আপনার।
প্র ০৪Variable font কি সবসময় ভালো? একটি ফাইলে অনেক ওজন — পারফরম্যান্স, নকশা আর font-variation-settings-এর ফাঁদ মিলিয়ে বিচার করুন।
২০১৬ সালের সেপ্টেম্বরে OpenType 1.8 ঘোষণা করা হয়, আর তাতে আসে variable font — অক্ষের ধারণাটি আসলে অনেক পুরোনো, Apple-এর TrueType GX আর Adobe-এর Multiple Master প্রযুক্তি ১৯৯০-এর দশকেই এমন কিছু করত, কিন্তু সর্বজনীন মান হয়নি। এবার চার বড় প্রতিষ্ঠান একসাথে আসায় ব্রাউজার আর অপারেটিং সিস্টেমে দ্রুত সমর্থন আসে। ভেতরের কৌশল হলো: ফন্টে প্রতিটি অক্ষরের একটি মূল আকার থাকে, আর প্রতিটি অক্ষের জন্য “এই দিকে গেলে কোন বিন্দু কতটা সরবে” তার তথ্য। ব্রাউজার মাঝামাঝি যেকোনো মানের আকার হিসাব করে বানায়।
সুবিধা স্পষ্ট। এক, অনুরোধ একটি — তিন-চারটি ওজন লাগলে মোট ডাউনলোডও প্রায়ই কম। দুই, নকশার স্বাধীনতা — শিরোনামে 750, মূল লেখায় 430, ফোনে একটু চাপা প্রস্থ, বড় পর্দায় চওড়া। তিন, opsz অক্ষ দিয়ে ছোট আকারে বেশি পাঠযোগ্য আর বড় আকারে বেশি সূক্ষ্ম অক্ষর, স্বয়ংক্রিয়ভাবে।
কিন্তু “সবসময়” নয়। শুধু Regular লাগলে একটি সাধারণ ফাইল variable ফাইলের চেয়ে ছোট — অক্ষের তথ্যের দাম আছে। বাংলা variable font কম (Anek Bangla-র মতো কয়েকটি আছে), আর প্রতিটি অক্ষ বাংলার সব যুক্তাক্ষরে সমান যত্নে বানানো কি না, নিজে দেখে নিতে হয়।
সবচেয়ে সাধারণ ভুলটি CSS-এর। font-variation-settings একটি মাত্র মান হিসেবে উত্তরাধিকারে যায়, অক্ষ ধরে ধরে নয়। ধরুন body-তে "wdth" 90, "GRAD" 50, আর একটি লিংকে শুধু "GRAD" 100 — লিংকে wdth আবার ডিফল্টে ফিরে যায়, কারণ পুরো তালিকাটাই বদলে গেছে। তাই নিয়ম: যেখানে পারেন font-weight, font-stretch, font-style ব্যবহার করুন — এগুলো আলাদা আলাদা উত্তরাধিকারে যায় আর cascade-এ ঠিকঠাক মেশে। নিজস্ব অক্ষ লাগলে প্রতিটি মান CSS variable-এ রেখে একটি নিয়মে জোড়া দেওয়ার কৌশল প্রচলিত (পর্ব ৩৩)।
মূল উপলব্ধি: variable font একটি হাতিয়ার, লক্ষ্য নয়। কয়টি ওজন সত্যিই লাগবে, তা আগে গুনুন — তারপর ঠিক করুন একটি variable ফাইল নাকি দুটি সাধারণ ফাইল।
প্র ০৫ব্রাউজারে তো zoom আছেই — তাহলে লেখার আকার px-এ না দিয়ে rem-এ দেওয়া নিয়ে এত জোর কেন? পাঠকের সেটিং, zoom আর fluid typography-র সম্পর্ক কী?
পাঠকের হাতে লেখা বড় করার দুটি আলাদা উপায় আছে। প্রথমটি zoom (Ctrl এবং +): পুরো পাতা — লেখা, ছবি, বাক্স, ফাঁক — সব একসাথে বড় হয়, আর বড় হলে CSS-এর px-ও বড় হয়। দ্বিতীয়টি ডিফল্ট লেখার আকার: ব্রাউজারের সেটিংসে “Font size: Large” বা ফোনের সিস্টেম-সেটিংসে বড় লেখা। এতে শুধু লেখার মূল আকার বদলায় — যা সাধারণত 16px, তা হয়ে যায় 20px বা আরও বেশি। অনেক বয়স্ক পাঠক আর চোখে কম দেখেন এমন মানুষ এই সেটিং একবার বদলে রাখেন, সব সাইটের জন্য।
এখানেই px-এর সমস্যা। আপনি p { font-size: 16px; } লিখলে সেই পাঠকের সেটিং আপনার পাতায় কোনো কাজ করে না — আপনি তাঁর পছন্দ উপেক্ষা করলেন। 1rem লিখলে সেটিং মানা হয়: তাঁর জন্য 1rem = 20px. তাই বিশেষজ্ঞরা লেখার আকার, আর অনেকে লেখার সাথে সম্পর্কিত ফাঁক ও media query-ও rem বা em-এ দেন। WCAG ১.৪.৪ (Resize Text) চায় লেখা ২০০% পর্যন্ত বড় করা গেলেও কিছু হারাবে না; zoom দিয়ে এটি প্রায়ই পূরণ হয়, কিন্তু পাঠকের ডিফল্ট মানাও একই মানসিকতার অংশ।
এবার fluid typography — পর্দার প্রস্থ অনুযায়ী লেখার আকার নিজে বাড়ে-কমে, যেমন font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem) (clamp() বিস্তারিত পর্ব ৩৫-এ)। এখানে একটি সূক্ষ্ম ফাঁদ আছে: যদি আকার শুধু vw-এ দেন (font-size: 2vw), তাহলে zoom করলে লেখা প্রায় বড়ই হয় না, কারণ zoom-এ viewport-এর CSS প্রস্থ ছোট হয়ে যায় আর 2vw-ও কমে। তাই fluid সূত্রে সবসময় একটি rem অংশ রাখুন, আর ওপরে-নিচে সীমা দিন।
আরেকটি বিষয়: “16px মূল লেখা” কোনো আইন নয়, শুরুর বিন্দু। বাংলায় অনেক ফন্টে মূল অক্ষর একই font-size-এ ছোট দেখায়, তাই 1.0625rem–1.125rem (17–18px) প্রায়ই আরামদায়ক — কিন্তু সেটাও rem-এ লিখুন।
মূল উপলব্ধি: লেখার আকার আপনার আর পাঠকের যৌথ সিদ্ধান্ত। rem সেই অংশীদারিত্বের ভাষা — আপনি অনুপাত ঠিক করেন, পাঠক মূল মাপ।
অনুশীলন
প্রথম দুটিতে পর্যবেক্ষণ আর ভুল খোঁজা, তৃতীয়টিতে হিসাব, চতুর্থটিতে একটি ছোট @font-face লিখবেন।
-
একটি পরিচিত সাইটের টাইপোগ্রাফি পড়ুন: আপনার পছন্দের একটি বাংলা খবরের সাইট খুলে মূল লেখার একটি অনুচ্ছেদে ডান-ক্লিক → Inspect. Computed ট্যাবে
font-family,font-size,line-heightআর অনুচ্ছেদের প্রস্থ লিখে রাখুন; নিচে “Rendered Fonts” দেখুন। তারপর এক লাইনে মোটামুটি কয়টি শব্দ, গুনে দেখুন। কী কী খুঁজবেন?দেখবেন
font-family-তে কয়েকটি নামের তালিকা — প্রায়ই একটি বাংলা ওয়েব ফন্ট আর শেষেsans-serif. “Rendered Fonts” জানাবে আসলে কোনটি এসেছে — হয়তো তালিকার প্রথমটি নয়!line-heightComputed-এ সবসময় px-এ দেখায় (হিসাবের পরের মান), তাই আসল CSS-এ এককহীন ছিল কি না জানতে Styles ট্যাবে নিয়মটি দেখুন। বাংলা খবরের সাইটে মূল লেখা সাধারণত 17–20px আর line-height 1.6–1.9. প্রতি লাইনে ৮–১৪টি বাংলা শব্দ আরামদায়ক; ২০টির বেশি হলে লাইন সম্ভবত খুব লম্বা। -
ভুল খুঁজুন: একজন সহকর্মী লিখেছেন —
body { font: 18px; line-height: 22px; text-align: justify; letter-spacing: 0.05em; }আরa { text-decoration: none; }. বাংলা ব্লগের জন্য এখানে কয়টি সমস্যা আছে, আর ঠিক রূপ কী?অন্তত পাঁচটি: (১)
font: 18pxঅবৈধ — family নেই, তাই পুরো ঘোষণা উপেক্ষিত। (২)line-height: 22pxস্থির আর বাংলার জন্য চাপা (18px ধরলে মাত্র 1.22 গুণ); সন্তানের লেখা বড় হলে লাইন উঠে যাবে। (৩) justify — ফোনে বড় ফাঁক আর river. (৪) বাংলায়letter-spacingঅক্ষর আলগা করে শব্দের গড়ন নষ্ট করে। (৫) লিংকের underline বাদ — শুধু রঙে চেনা যায়, WCAG ১.৪.১. ঠিক রূপ:body { font: 1.125rem/1.7 "Hind Siliguri", system-ui, sans-serif; text-align: start; } a { text-underline-offset: 0.2em; } /* underline থাকল, শুধু সুন্দর হলো */ -
নিজের type scale হিসাব করুন: মূল আকার 1rem, অনুপাত 1.2. h4 থেকে h1 পর্যন্ত চারটি ধাপের মান rem আর px-এ (1rem = 16px ধরে) বের করুন। পাঠক ডিফল্ট 20px করলে h1 কত px হবে?
h4 = 1.2rem (19.2px), h3 = 1.44rem (23.04px), h2 = 1.728rem (27.65px), h1 = 2.074rem (33.18px) — প্রতিটি আগেরটির ১.২ গুণ। পাঠক ডিফল্ট 20px করলে h1 = 2.074 × 20 = প্রায় 41.5px — পুরো স্কেল একই অনুপাতে বড় হয়, ছন্দ ঠিক থাকে। px-এ লিখলে h1 থাকত 33px আর মূল লেখাও 16px — পাঠকের সেটিং পুরো উপেক্ষিত।
-
একটি self-hosted variable font: আপনার সাইটের
/fonts/ফোল্ডারেnoto-sans-bengali-var.woff2নামের একটি variable font আছে, ওজন 100–900. এর জন্য@font-faceলিখুন, আর head-এ এটি আগেভাগে নামানোর লিংক দিন। শিরোনামে 700 আর মূল লেখায় 400 ব্যবহার করুন।/* head-এ: <link rel="preload" href="/fonts/noto-sans-bengali-var.woff2" as="font" type="font/woff2" crossorigin> */ @font-face { font-family: "Noto Sans Bengali"; src: url("/fonts/noto-sans-bengali-var.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; } body { font-family: "Noto Sans Bengali", system-ui, sans-serif; font-weight: 400; } h1, h2 { font-weight: 700; }মূল বিষয়:
font-weight-এ দুটি সংখ্যা (পরিসর), শুধু woff2,font-display: swap. preload-এcrossoriginবাধ্যতামূলক — ফন্ট সবসময় CORS মোডে নামে, এটি না দিলে ব্রাউজার ফাইলটি দুবার নামাতে পারে। একটিই ফাইল, তাই 400 আর 700 দুটোর জন্য আলাদা ডাউনলোড নেই।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমfont-display: swap দেওয়া একটি ওয়েব ফন্ট লোডের ঘটনাগুলো সময়ের ক্রমে সাজান (▲▼ চেপে সরান)
- ব্রাউজার দেখে কোনো লেখার জন্য ফন্টটি দরকার
- woff2 ফাইলের ডাউনলোড শুরু হয়
- খুব ছোট block period — লেখা অদৃশ্য
- লেখা fallback ফন্টে দেখা যায়
- ফন্ট এসে লেখা বদলায়, লেআউট একটু সরে
মা-element-এ font-size: 14px আর সন্তান শিরোনামে font-size: 28px. শিরোনামের লাইনগুলো যেন গায়ে না ওঠে, তার জন্য মা-element-এ কোন line-height সবচেয়ে ভালো?
line-height: 1.5emline-height: 150%line-height: 1.5line-height: 21px
নিচের কোন font shorthand বৈধ?
font: bold 16px;font: italic 600 1rem/1.6 Georgia, serif;font: sans-serif 16px;font: 700 Arial, sans-serif;
@font-face-এ font-display: swap দিলে ধীর নেটওয়ার্কে কী ঘটে?
- ফন্ট আসা পর্যন্ত প্রায় ৩ সেকেন্ড লেখা অদৃশ্য থাকে
- ফন্ট তখনই না থাকলে এই পাতায় আর কখনো ব্যবহার হয় না
- ধীর নেট বুঝে ব্রাউজার ফন্টটি একদমই নামায় না
- লেখা প্রায় সঙ্গে সঙ্গে fallback ফন্টে দেখায়, ফন্ট এলে বদলে যায়
লম্বা প্রবন্ধের অনুচ্ছেদের প্রস্থ সীমিত রাখতে কোন CSS সবচেয়ে উপযোগী?
max-width: 65chwidth: 1200pxwidth: 100vwletter-spacing: 0.1em
একটি সরু কার্ডে লম্বা URL কার্ড ছাপিয়ে বাইরে চলে যাচ্ছে, ফোনে পুরো পাতা পাশে সরে। সবচেয়ে উপযুক্ত সমাধান কোনটি?
- URL-এ
white-space: nowrap - URL-এ
overflow-wrap: anywhere - পুরো body-তে
word-break: break-all - URL-এ
hyphens: auto
text-wrap: balance সাধারণত কোথায় ব্যবহার করা হয়?
- পুরো প্রবন্ধের লম্বা অনুচ্ছেদে
- ফর্মের ইনপুট বক্সে
- শিরোনাম আর ছোট ক্যাপশনে
- কোড ব্লকে
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- font stack: নির্দিষ্ট ফন্ট আগে, generic family (
sans-serif,serif,monospace,system-ui) সবার শেষে; ব্রাউজার প্রতিটি অক্ষরের জন্য তালিকা ধরে খোঁজে। - আকার rem-এ, একটি type scale ধরে; ফন্টে যে ওজন আছে শুধু সেগুলোই আসে;
fontshorthand-এ আকার আর family বাধ্যতামূলক, বাকিগুলো রিসেট হয়। - line-height এককহীন (বাংলায় 1.6–1.8); লাইনের দৈর্ঘ্য
max-width: 65ch-এর কাছাকাছি; লম্বা লেখায়text-align: start, justify নয়; লিংকে underline রাখুন। - শিরোনামে
text-wrap: balance(Baseline Newly available), লম্বা URL-এoverflow-wrap: anywhere,hyphens: auto-এর জন্য সঠিকlang. @font-face-এ শুধু woff2 +font-display: swap; কম ওজন বা একটি variable font; self-hosting ভাবুন; fallback-এর আকার মেলাতেfont-size-adjust.
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ২২ · ব্যাকগ্রাউন্ড, gradient, বর্ডার আর ছায়াপরবর্তী পর্ববাক্সকে রং, ছবি, gradient, বর্ডার আর ছায়ায় সাজানো।
- পর্ব ১৪ · ওয়েবে বাংলা — UTF-8, lang, বাংলা ফন্ট আর টাইপোগ্রাফিবাংলার বিশেষ নিয়মযুক্তাক্ষর, বাংলা ওয়েব ফন্টের তালিকা, বাংলার line-height আর বাংলা অঙ্ক।
- HTML ও CSS · কোর্স হোম৫৯টি পর্বপুরো কোর্সের রোডম্যাপ — প্রথম পেজ থেকে আধুনিক রেসপন্সিভ ডিজাইন।
- কম্পিউটার ও ICT · বাংলা টাইপিং ও Unicodeপাশের ট্র্যাকঅভ্র আর বিজয়, ANSI বনাম Unicode ফন্ট — ফন্টের সমস্যা কোথা থেকে আসে।