বর্ডার, ব্যাকগ্রাউন্ড গ্রেডিয়েন্ট বা ছদ্ম-এলিমেন্ট দিয়ে নকল করার পরিবর্তে, আন্ডারলাইন, ওভারলাইন ও স্ট্রাইকথ্রু স্টাইল করতে নেটিভ text-decoration প্রপার্টি ব্যবহার করুন। নেটিভ ডেকোরেশন র্যাপ করা লাইন জুড়ে টেক্সট ফলো করে, ফন্টের মেট্রিক ট্র্যাক করে, গ্লিফ ডিসেন্ডার এড়িয়ে যায় এবং নেস্টেড এলিমেন্টের মাধ্যমে ইনহেরিট করে, তাই এর কোনওটিই আবার প্রয়োগ করার প্রয়োজন হয় না। এই গাইডের শেষে বক্স-ভিত্তিক টেকনিকের জন্য তখনই পৌঁছান যখন সাজসজ্জা অবশ্যই টেক্সটের সাথে চলার পরিবর্তে টেক্সটকে আউটলাইন বা র্যাপ করতে হবে।
টেক্সট ডেকোরেশন যেকোনও টেক্সটের ক্ষেত্রে প্রযোজ্য, শুধু লিঙ্কের ক্ষেত্রে নয়। যেখানে আন্ডারলাইন করা টেক্সট কোনও লিঙ্ক নয়, সেখানে নিশ্চিত করুন যে এটি ভুল করে লিঙ্ক হিসেবে দেখানো হচ্ছে না। কোনও লিঙ্ক সাজানোর সময়, স্ক্রিপ্ট হ্যান্ডলার সহ href="javascript:void(0)" নয়, গন্তব্যের দিকে নির্দেশ করে এমন আসল <a href> ব্যবহার করুন (নতুন ট্যাব খুলতে target="_blank" rel="noopener" যোগ করুন)। আসল লিঙ্কে মিডল-ক্লিক, কপি-লিঙ্ক ও স্ক্রিন রিডার সংক্রান্ত আচরণ বজায় থাকে।
লাইন স্টাইল করুন
text-decoration শর্টহ্যান্ডের মাধ্যমে লাইন, স্টাইল, রঙ ও ঘনত্ব এবং text-underline-offset-এর মাধ্যমে টেক্সট থেকে ব্যবধান সেট করুন। :where()-এ সিলেক্টর র্যাপ করুন যাতে ডিফল্টের কোনও নির্দিষ্টতা না থাকে এবং কাস্টম প্রপার্টির প্রয়োজন ছাড়াই পরে যেকোনও ওভাররাইড কাজ করে।
:where(.decorated) {
/* Thickness is relative to the font size (0.08em is an example value), so the line is not too heavy
on small text or too light on large text, and max() keeps it at least 1px so it never disappears. */
text-decoration: underline solid currentColor max(1px, 0.08em);
/* Use em so the gap scales with the font size. 0.2em clears most descenders; example value. */
text-underline-offset: 0.2em;
}
/* Example hover state: a softer line that firms up on hover and focus. The 50% mix and
0.12em thickness are example values. */
:where(.decorated) {
text-decoration-color: color-mix(in srgb, currentColor, transparent);
}
:where(.decorated:is(:hover, :focus-visible)) {
text-decoration-color: currentColor;
text-decoration-thickness: max(1px, 0.12em);
}
/* Other lines are a different text-decoration-line on the same properties */
.decorated-over { text-decoration-line: overline; }
.decorated-through { text-decoration-line: line-through; }
text-decoration-style-এ solid, double, dotted, dashed ও wavy কাজ করে। text-underline-offset শুধুমাত্র আন্ডারলাইনের ক্ষেত্রে প্রযোজ্য।
ডিজাইন শুরু করার পয়েন্ট:
- ঘনত্ব: বডি টেক্সটের জন্য প্রায়
0.06emথেকে0.1em। শিরোনাম ও জোর দেওয়া অবস্থার জন্য আরও মোটা (0.1emথেকে0.15em) করুন। - অফসেট: প্রায়
0.15emথেকে0.25em। ডটেড ও ঢেউ খেলানো লাইনের জন্য সলিড লাইনের চেয়ে একটু বেশি জায়গা প্রয়োজন, তাই সেগুলির জন্য অফসেট বাড়ান। - রঙ:
currentColorটেক্সটের সাথে লাইনের রঙ ম্যাচ করে। টেক্সটের রঙের একটি হালকা মিশ্রণ যা হোভার করার সময় আরও স্পষ্ট হয়ে ওঠে, তা লিঙ্কের দীর্ঘ রানকে শান্ত রাখে। - স্টাইল: লিঙ্কের জন্য
solid, শব্দ ও সংক্ষিপ্ত রূপের জন্যdottedএবং ত্রুটির মতো অ্যানোটেশনের জন্যwavy।
কোথায় লাইন স্কিপ করা হয়েছে তা নিয়ন্ত্রণ করুন
ইঙ্ক স্কিপিং
ডিফল্ট হিসেবে, আন্ডারলাইন ও ওভারলাইন গ্লিফ অংশের চারপাশে ভেঙে যায় যা তাদের ক্রস করে, যেমন ডিসেন্ডার। আচরণ বেছে নিতে text-decoration-skip-ink সেট করুন:
.decorated {
/* auto: skip ink for most scripts (default). none: draw straight through.
all: also skip ink in scripts where auto does not, such as Japanese or Chinese. */
text-decoration-skip-ink: all;
}
- ল্যাটিন টেক্সটের জন্য
autoরাখুন এবং এটি ঘোষণা করবেন না: এটি ডিফল্ট। - আইডিওগ্রাফিক গ্লিফ ক্রস করার জন্য আন্ডারলাইন বেসলাইনের যথেষ্ট কাছাকাছি থাকলে অথবা মিক্সড-স্ক্রিপ্ট টেক্সট একই রকম দেখাতে হলে
allব্যবহার করুন। - খুব মোটা বা ইচ্ছাকৃতভাবে আলঙ্কারিক লাইনের জন্য
noneব্যবহার করুন, যেখানে ফাঁকগুলি বিরতির মতো দেখাবে।
স্পেস এড়িয়ে যান
text-decoration-skip-spaces ঠিক করে যে স্পেসের নিচে লাইন আঁকা হবে কিনা। ডিফল্ট, start end, শুরুতে ও শেষে স্পেস ডেকোরেট না করে ছেড়ে দেয়।
.decorated {
/* Spaces collapse by default, so there is nothing to skip. Preserve them when the
leading or trailing spaces are meaningful, such as padded input values. */
white-space: pre;
/* none: decorate every space. all: skip every space, so each word is underlined separately.
start | end | start end: skip only leading, trailing, or both. */
text-decoration-skip-spaces: all;
}
text-decoration-skip-spaces ঘোষণা করবেন না, যদি না ডেকোরেশন দৃশ্যত প্যাডিং (none) কভার করে বা প্রতিটি শব্দের মধ্যে ব্রেক (all) থাকে। সাধারণ ইনলাইন টেক্সট, যেমন লিঙ্কের টেক্সটে কোনও লিডিং বা ট্রেলিং স্পেস থাকে না, তাই ঘোষণাটি কিছুই করে না।
ইনসেট সহ লাইনটি ট্রিম বা এক্সটেন্ড করুন
text-decoration-inset লাইনের শুরু ও শেষ সরায়। পজিটিভ ভ্যালু কোনও প্রান্তকে ভিতরের দিকে টানে, নেগেটিভ ভ্যালু এটিকে বাইরের দিকে ঠেলে দেয়। একটি ভ্যালু দুই প্রান্তেই কাজ করে; দুটি ভ্যালু আলাদাভাবে শুরু ও শেষ সেট করে। শতাংশ সাজানো বক্সের ইনলাইন সাইজকে বোঝায়।
/* Small insets soften the ends of the line; larger ones read as a deliberately short line.
Both values are examples. */
.trimmed { text-decoration-inset: var(--deco-inset, 0.1em); }
.extended { text-decoration-inset: calc(var(--deco-inset, 0.1em) * -1); }
বর্ডার বা ব্যাকগ্রাউন্ড গ্রেডিয়েন্ট ছাড়া হোভার করার সময় আন্ডারলাইন দেখাতে, শেষ অংশ ১০০% ট্রিম করুন এবং এটি ০-তে ট্রানজিশন করুন:
.reveal {
text-decoration: underline; /* Always visible, including for reduced motion */
}
/* Only hide and animate the line when the user has not asked for reduced motion. */
@media (prefers-reduced-motion: no-preference) {
.reveal {
/* Trim the end by the full inline size so the line starts with zero length. */
text-decoration-inset: 0 100%;
/* 150ms to 300ms feels responsive without lagging; ease-out starts quickly. Example values. */
transition: text-decoration-inset var(--reveal-duration, 0.25s) ease-out;
}
/* Include :focus-visible so keyboard users get the same reveal as pointer users. */
.reveal:is(:hover, :focus-visible) {
text-decoration-inset: 0 0;
}
}
সিউডো-এলিমেন্ট ব্যবহার করে কাস্টম লাইন আঁকা
লাইনটি এমন একটি আকার হতে হবে যা text-decoration আঁকতে পারে না, যেমন একটি স্কুইগল, এবং ক্লিপিংয়ের মাধ্যমে এটি প্রকাশ করতে হবে, তখন একটি ছদ্ম-উপাদান ব্যবহার করুন। কোনও অতিরিক্ত মার্কআপের প্রয়োজন নেই, তাই লিঙ্কটি সাধারণ <a> হিসেবেই থাকে।
<a class="draw" href="#">Hover to draw underline</a>
.draw {
position: relative;
display: inline-block;
color: inherit;
text-decoration: none;
padding-block-end: 0.4em; /* Space for the line below the text; example value */
}
.draw::after {
content: "";
position: absolute;
inset: auto 0 0 0;
block-size: 0.4em; /* Height of the squiggle; example value */
pointer-events: none;
border: var(--deco-thickness, max(1px, 0.08em)) solid var(--deco-color, currentColor);
/* A single shape strokes along its path, using the border width as the stroke. Example squiggle. */
border-shape: shape(from 0% 50%,
curve to 20% 50% with 5% 0% / 15% 100%,
smooth to 40% 50% with 35% 100%,
smooth to 60% 50% with 55% 100%,
smooth to 80% 50% with 75% 100%,
smooth to 100% 50% with 95% 100%);
}
/* Only hide and animate the line when the user has not asked for reduced motion;
otherwise it stays fully drawn. */
@media (prefers-reduced-motion: no-preference) {
.draw::after {
/* Clip the line away from the right edge. The negative block insets keep the stroke
from being cut off vertically. */
clip-path: inset(-1em 100% -1em 0);
/* A slightly slower draw than a hover reveal reads as drawing; example duration. */
transition: clip-path var(--draw-duration, 0.6s) ease-out;
}
.draw:is(:hover, :focus-visible)::after {
clip-path: inset(-1em 0 -1em 0); /* Fully drawn */
}
}
পরিবর্তে একটি বক্স দিয়ে টেক্সট আউটলাইন করুন
দুটি বক্স প্রপার্টি টেক্সটের সাথে লাইন দেখানোর পরিবর্তে টেক্সটের আউটলাইন দেখিয়ে সেটি সাজায়। টেক্সট প্যাডিং দিন যাতে আউটলাইন এটি স্পর্শ না করে।
/* Gradient outline with a see-through middle */
.ring {
padding: 0.2em 0.75em; /* Example values: enough room that the outline does not touch the text */
/* The border width is the visible outline thickness. Relative to the font size, with a 2px
minimum so it stays visible on small text; example value. */
border: var(--ring-width, max(2px, 0.12em)) solid transparent;
background: linear-gradient(135deg, var(--ring-start, #2563eb), var(--ring-end, #db2777)) border-box;
/* Paint the background only under the border, so the inside stays transparent. */
background-clip: border-area;
}
/* Border that follows a shape that border-radius cannot draw, such as a tag with a pointed end */
.tag {
padding: 0.2em 1.5em 0.2em 0.9em; /* Example values: extra room at the point so the text is not clipped */
border: var(--shape-stroke, max(2px, 0.08em)) solid var(--shape-color, currentColor); /* Example stroke width */
/* A single shape strokes along its path. Two shapes fill the area between them.
This polygon is an example; use shape() for curves. */
border-shape: polygon(0 0, 85% 0, 100% 50%, 85% 100%, 0 100%);
}
border-shape শুধুমাত্র বর্ডার পরিবর্তন করে। ব্যাকগ্রাউন্ড এখনও আয়তাকার বক্স, তাই কোনও আকার পূরণ করার জন্য এটির উপর নির্ভর করবেন না।
শুধুমাত্র কোণগুলির জন্য আলাদা আকৃতির প্রয়োজন হলে, যেমন বেভেলড, স্কুপড বা খাঁজকাটা লেবেল, পরিবর্তে border-radius-এর সাথে corner-shape ব্যবহার করুন। এটি ব্যাকগ্রাউন্ড ও বর্ডারকে কোণ অনুযায়ী রাখে এবং কাজ করে না এমন ব্রাউজার সাধারণ গোলাকার কোণে ফিরে যায়।
.label {
padding: 0.2em 0.9em; /* Example values */
border: var(--shape-stroke, max(2px, 0.08em)) solid var(--shape-color, currentColor);
border-radius: 0.6em; /* Corner size; example value */
corner-shape: bevel; /* round (default) | scoop | bevel | notch | square | squircle */
}
একটি কৌশল বেছে নিন
text-decoration(লাইন, ইঙ্ক স্কিপিং, স্পেস, ইনসেট): লাইনটি টেক্সটের সাথে সাথে চলতে হবে, এটির সাথে মোড়ানো এবং এর ফন্ট মেট্রিক্স অনুসরণ করতে হবে। এটি ডিফল্ট পছন্দ।border-shapeওclip-pathসহ সিউডো-এলিমেন্ট: লাইনটি কাস্টম শেপের অথবা ড্র-অন অ্যানিমেশন প্রয়োজন। এটি শুধুমাত্র তখনই বেছে নিন যখনtext-decoration-styleলুক তৈরি করতে পারে না, কারণ এটির জন্য অতিরিক্ত পজিশনিং প্রয়োজন।background-clip: border-area: টেক্সটে গ্রেডিয়েন্ট আউটলাইন প্রয়োজন। সলিড আউটলাইন যথেষ্ট হলে, সাধারণborder-colorব্যবহার করুন।corner-shape: শুধু কোণগুলির জন্য আলাদা আকৃতির প্রয়োজন, যেমন বেভেলড, স্কুপড বা খাঁজকাটা।border-radius-এর সাথে এটি পেয়ার করুন, যা কোণের সাইজ সেট করে।border-shape: আউটলাইনের জন্য এমন একটি আকার প্রয়োজন যাborder-radiusআঁকতে পারে না, যেমন ট্যাগ বা তীরচিহ্ন। কোণগুলি গোলাকার হলেই যথেষ্ট হলেborder-radiusব্যবহার করুন।- ইনসেট হোভার রিভিল: রঙ পরিবর্তন ছাড়াও কোনও লিঙ্কে হোভার করার সুবিধা যোগ করার প্রয়োজন হলে এটি যোগ করা যেতে পারে। ইন্টার্যাক্টিভ নয় এমন টেক্সটের ক্ষেত্রে এটি এড়িয়ে যান।
ফলব্যাক স্ট্র্যাটেজি
প্রতিটি ফলব্যাক টেক্সটকে পাঠযোগ্য রাখে এবং মূল সজ্জা বজায় রাখে। আপনার বেসলাইন টার্গেটের পরিপ্রেক্ষিতে প্রয়োজনীয়তা ফ্রেম করুন: যদি এতে প্রপার্টি ছাড়া ব্রাউজার অন্তর্ভুক্ত থাকে, তাহলে ম্যাচিং ফলব্যাক প্রয়োগ করুন।
ইঙ্ক স্কিপিং all
আপনার বেসলাইন টার্গেট text-decoration-skip-ink: all সাপোর্ট না করলে, ঘোষণাটি উপেক্ষা করা হয় এবং ব্রাউজার auto রাখে। ল্যাটিন ডিসেন্ডার এখনও এড়িয়ে যাওয়া হয়; শুধুমাত্র auto-এ কভার করা হয় না এমন স্ক্রিপ্ট, যেমন জাপানি, ইঙ্ক স্কিপিং হারায়। এটি হল গ্রেসফুল ডিগ্রেডেশন, তাই কোনও অতিরিক্ত কোডের প্রয়োজন নেই।
স্পেস এড়িয়ে যান
আপনার বেসলাইন টার্গেট text-decoration-skip-spaces-এ কাজ না করলে, ব্রাউজার স্পেসের নিজস্ব ডিফল্ট হ্যান্ডলিং ব্যবহার করে। এটি হল গ্রেসফুল ডিগ্রেডেশন: ব্রাউজার যেসব স্পেস এড়িয়ে যায় না, সেগুলির নিচে লাইন টানা হয়।
ইনসেট
আপনার বেসলাইন টার্গেট text-decoration-inset-এ কাজ না করলে,
ঘোষণাটি উপেক্ষা করা হয়, তাই লিঙ্কটি তার স্বাভাবিক, সম্পূর্ণ দৃশ্যমান আন্ডারলাইন রাখে
এবং ট্রানজিশনে অ্যানিমেট করার কিছু থাকে না। এটি হল গ্রেসফুল ডিগ্রেডেশন: হোভার রিভিল হারিয়ে যায় এবং লিঙ্কটি আন্ডারলাইন করা থাকে।
সীমান্তবর্তী এলাকা
আপনার বেসলাইন টার্গেট background-clip: border-area-কে সাপোর্ট না করলে, ডিক্লারেশন উপেক্ষা করা হয় এবং ব্যাকগ্রাউন্ড সম্পূর্ণ বর্ডার বক্সের নিচে পেইন্ট করে, শুধু আউটলাইনের পরিবর্তে টেক্সট ফিল করে। ডিজাইনের অংশ হিসেবে গ্রেডিয়েন্ট থাকলে, সাধারণ সলিড বর্ডার ব্যবহার করবেন না। পরিবর্তে, গ্রেডিয়েন্ট আবার তৈরি করুন এবং শুধুমাত্র @supports-এর মধ্যে background-clip: border-area প্রয়োগ করুন।
এলিমেন্টের ব্যাকগ্রাউন্ড কোনও পরিচিত ফ্ল্যাট কালার হলে, একটি অস্বচ্ছ লেয়ার ব্যবহার করুন। প্যাডিং বক্সের উপরে সারফেস কালার এবং বর্ডার বক্সের নিচে গ্রেডিয়েন্ট পেইন্ট করুন, যাতে গ্রেডিয়েন্ট শুধুমাত্র স্বচ্ছ বর্ডারের মাধ্যমে দেখা যায়:
.ring {
border: var(--ring-width, max(2px, 0.12em)) solid transparent; /* Example width */
/* Fallback: an opaque surface layer hides the gradient inside the border. */
background:
linear-gradient(var(--surface, canvas) 0 100%) padding-box,
linear-gradient(135deg, var(--ring-start, #2563eb), var(--ring-end, #db2777)) border-box;
}
@supports (background-clip: border-area) {
.ring {
background: linear-gradient(135deg, var(--ring-start, #2563eb), var(--ring-end, #db2777)) border-box;
background-clip: border-area; /* The inside stays transparent */
}
}
ভিতরের অংশ স্বচ্ছ রাখতে হলে মাস্ক করা ছদ্ম-এলিমেন্ট ব্যবহার করুন। সিউডো-এলিমেন্ট গ্রেডিয়েন্ট বহন করে এবং একটি মাস্ক প্যাডিং রিং ছাড়া সবকিছু কেটে দেয়:
@supports not (background-clip: border-area) {
.ring {
position: relative;
border-color: transparent;
}
.ring::before {
content: "";
position: absolute;
inset: calc(var(--ring-width, max(2px, 0.12em)) * -1); /* Cover the border box */
padding: var(--ring-width, max(2px, 0.12em)); /* Ring thickness */
border-radius: inherit;
background: linear-gradient(135deg, var(--ring-start, #2563eb), var(--ring-end, #db2777));
/* Keep only the area between the content box and the border box. */
mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
mask-composite: exclude;
pointer-events: none;
}
}
বর্ডারের আকৃতি
আপনার বেসলাইন টার্গেটে border-shape কাজ না করলে, ঘোষণাটি উপেক্ষা করা হয় এবং এলিমেন্টটি তার আয়তাকার বর্ডার বজায় রাখে। শেপটি শুধুমাত্র আলঙ্কারিক হলে, গোলাকার কোণযুক্ত আয়তক্ষেত্রকে ফলব্যাক হিসেবে গ্রহণ করা যেতে পারে। আকারটি যখন কোনও অর্থ বহন করে, যেমন ট্যাগ, তীরচিহ্ন বা কলআউট, তখন এটিকে যতটা সম্ভব কাছাকাছি পুনরুৎপাদন করুন এবং শুধুমাত্র @supports-এর ভিতরে border-shape প্রয়োগ করুন।
ক্লিপ করা ছদ্ম-এলিমেন্ট দিয়ে আউটলাইন আঁকুন। একটি স্বচ্ছ বর্ডার রাখুন যাতে বক্সটি সমর্থিত কেসের মতো একই আকারের হয়, ছদ্ম-উপাদানটি আউটলাইন রঙ দিয়ে পূরণ করুন এবং এটিকে একটি রিংয়ে কাটুন evenodd clip-path: বাইরের আকৃতি, তারপর স্ট্রোক প্রস্থ দ্বারা একই আকৃতির ইনসেট।
.tag {
--stroke: max(2px, 0.08em); /* Example stroke width */
position: relative;
padding: 0.2em 1.5em 0.2em 0.9em; /* Example values */
border: var(--stroke) solid transparent;
}
@supports not (border-shape: circle(50%)) {
.tag::before {
content: "";
position: absolute;
inset: calc(var(--stroke) * -1); /* Cover the border box */
background: var(--shape-color, currentColor);
pointer-events: none;
/* Outer shape, then the inner shape inset by the stroke. The inner points are approximate on
diagonal edges, so the stroke looks slightly thinner there. */
clip-path: polygon(evenodd,
0 0, 85% 0, 100% 50%, 85% 100%, 0 100%,
var(--stroke) var(--stroke),
calc(85% - var(--stroke)) var(--stroke),
calc(100% - var(--stroke) * 2) 50%,
calc(85% - var(--stroke)) calc(100% - var(--stroke)),
var(--stroke) calc(100% - var(--stroke)));
}
}
@supports (border-shape: circle(50%)) {
.tag {
border-color: var(--shape-color, currentColor);
border-shape: polygon(0 0, 85% 0, 100% 50%, 85% 100%, 0 100%);
}
}
আউটলাইনের পরিবর্তে ভরাট করা আকারের জন্য, এলিমেন্টে সরাসরি একই পয়েন্ট সহ clip-path: polygon(...) লিখুন।
সিউডো-এলিমেন্ট আন্ডারলাইনের জন্য, .draw::after-এ border-block-end দিয়ে একটি সরলরেখা আঁকুন এবং শুধুমাত্র @supports (border-shape: circle(50%))-এর মধ্যে block-size, border ও border-shape স্কুইগল প্রয়োগ করুন। লাইনটি সোজা হলেও আঁকা হচ্ছে, কারণ clip-path অ্যানিমেশন আকারের উপর নির্ভর করে না।
এছাড়াও, clip-path ফোকাস রিং ও box-shadow ক্লিপ করে। ফোকাস দেখানোর জন্য ক্লিপ করা এলিমেন্টের আউটলাইনের উপর নির্ভর করবেন না; পরিবর্তে রঙ বা ব্যাকগ্রাউন্ড পরিবর্তন করে :focus-visible স্টাইল করুন।