নতুন CSS টাইপ অবজেক্ট মডেলের সাথে কাজ করা

এরিক বিডেলম্যান

টিএল; ডিআর

CSS এখন জাভাস্ক্রিপ্টে মান নিয়ে কাজ করার জন্য একটি সঠিক অবজেক্ট-ভিত্তিক API আছে।

el.attributeStyleMap.set('padding', CSS.px(42));
const padding = el.attributeStyleMap.get('padding');
console.log(padding.value, padding.unit); // 42, 'px'

স্ট্রিং এবং সূক্ষ্ম বাগ একত্রিত করার দিন শেষ!

ভূমিকা

পুরানো CSSOM

CSS এর অনেক বছর ধরে একটি অবজেক্ট মডেল (CSSOM) আছে । প্রকৃতপক্ষে, আপনি যখনই জাভাস্ক্রিপ্টে .style পড়তে/সেট করেন তখন আপনি এটি ব্যবহার করছেন:

// Element styles.
el.style.opacity = 0.3;
typeof el.style.opacity === 'string' // Ugh. A string!?

// Stylesheet rules.
document.styleSheets[0].cssRules[0].style.opacity = 0.3;

নতুন CSS টাইপ OM

নতুন CSS টাইপড অবজেক্ট মডেল (টাইপড OM), Houdini প্রচেষ্টার অংশ, CSS মানগুলিতে ধরন, পদ্ধতি এবং একটি সঠিক অবজেক্ট মডেল যোগ করে এই বিশ্বদর্শনকে প্রসারিত করে। স্ট্রিংয়ের পরিবর্তে, মানগুলিকে জাভাস্ক্রিপ্ট অবজেক্ট হিসাবে প্রকাশ করা হয় যাতে CSS-এর কার্যকারিতা (এবং বুদ্ধিমান) ম্যানিপুলেশন সহজতর হয়।

element.style ব্যবহার করার পরিবর্তে, আপনি উপাদানগুলির জন্য একটি নতুন .attributeStyleMap বৈশিষ্ট্য এবং স্টাইলশীট নিয়মগুলির জন্য একটি .styleMap বৈশিষ্ট্যের মাধ্যমে শৈলীগুলি অ্যাক্সেস করবেন৷ উভয়ই একটি StylePropertyMap অবজেক্ট প্রদান করে।

// Element styles.
el.attributeStyleMap.set('opacity', 0.3);
typeof el.attributeStyleMap.get('opacity').value === 'number' // Yay, a number!

// Stylesheet rules.
const stylesheet = document.styleSheets[0];
stylesheet.cssRules[0].styleMap.set('background', 'blue');

যেহেতু StylePropertyMap হল মানচিত্রের মতো বস্তু, তারা সমস্ত স্বাভাবিক সন্দেহভাজনকে সমর্থন করে (get/set/keys/values/entries), তাদের সাথে কাজ করার জন্য নমনীয় করে তোলে:

// All 3 of these are equivalent:
el.attributeStyleMap.set('opacity', 0.3);
el.attributeStyleMap.set('opacity', '0.3');
el.attributeStyleMap.set('opacity', CSS.number(0.3)); // see next section
// el.attributeStyleMap.get('opacity').value === 0.3

// StylePropertyMaps are iterable.
for (const [prop, val] of el.attributeStyleMap) {
  console.log(prop, val.value);
}
// → opacity, 0.3

el.attributeStyleMap.has('opacity') // true

el.attributeStyleMap.delete('opacity') // remove opacity.

el.attributeStyleMap.clear(); // remove all styles.

মনে রাখবেন যে দ্বিতীয় উদাহরণে, opacity স্ট্রিং ( '0.3' ) এ সেট করা আছে কিন্তু সম্পত্তিটি পরে আবার পড়া হলে একটি সংখ্যা ফিরে আসে।

সুবিধা

তাহলে সিএসএস টাইপড ওএম কোন সমস্যা সমাধানের চেষ্টা করছে? উপরের উদাহরণগুলির দিকে তাকিয়ে (এবং এই নিবন্ধের বাকি অংশ জুড়ে), আপনি যুক্তি দিতে পারেন যে CSS টাইপ করা OM পুরানো অবজেক্ট মডেলের চেয়ে অনেক বেশি ভার্বোস। আমি রাজি হবে!

টাইপ করা OM লেখা বন্ধ করার আগে, এটি টেবিলে নিয়ে আসা কিছু মূল বৈশিষ্ট্য বিবেচনা করুন:

  • কম বাগ . যেমন সাংখ্যিক মান সবসময় সংখ্যা হিসাবে ফেরত দেওয়া হয়, স্ট্রিং নয়।

    el.style.opacity += 0.1;
    el.style.opacity === '0.30.1' // dragons!
    
  • পাটিগণিত অপারেশন এবং ইউনিট রূপান্তর । পরম দৈর্ঘ্য একক (যেমন px -> cm ) মধ্যে রূপান্তর করুন এবং মৌলিক গণিত করুন

  • মান ক্ল্যাম্পিং এবং রাউন্ডিং । OM রাউন্ড এবং/অথবা ক্ল্যাম্পের মান টাইপ করা হয়েছে যাতে তারা একটি সম্পত্তির জন্য গ্রহণযোগ্য সীমার মধ্যে থাকে।

  • আরও ভালো পারফরম্যান্স । ব্রাউজারটিকে স্ট্রিং মানগুলিকে সিরিয়ালাইজ করা এবং ডিসিরিয়ালাইজ করার জন্য কম কাজ করতে হবে। এখন, ইঞ্জিন JS এবং C++ জুড়ে CSS মানগুলির অনুরূপ বোঝাপড়া ব্যবহার করে। Tab Akins কিছু প্রারম্ভিক পারফ বেঞ্চমার্ক দেখিয়েছে যেগুলি পুরানো CSSOM এবং স্ট্রিং ব্যবহার করার তুলনায় অপারেশন/সেকেন্ডে Typed OM কে ~30% দ্রুত রাখে। requestionAnimationFrame() ব্যবহার করে দ্রুত CSS অ্যানিমেশনের জন্য এটি তাৎপর্যপূর্ণ হতে পারে। crbug.com/808933 ব্লিঙ্কে অতিরিক্ত কর্মক্ষমতা কাজ ট্র্যাক করে।

  • ত্রুটি পরিচালনা . নতুন পার্সিং পদ্ধতি CSS এর জগতে ত্রুটি পরিচালনা করে।

  • "আমি কি উট-কেসযুক্ত CSS নাম বা স্ট্রিং ব্যবহার করব?" নামগুলি উট-কেস বা স্ট্রিং (যেমন el.style.backgroundColor বনাম el.style['background-color'] ) কিনা তা অনুমান করার আর কিছু নেই। টাইপ করা OM-এ CSS প্রপার্টির নাম সবসময় স্ট্রিং হয়, যা আপনি আসলে CSS-এ যা লিখেছেন তার সাথে মিলে যায় :)

ব্রাউজার সমর্থন এবং বৈশিষ্ট্য সনাক্তকরণ

টাইপ করা OM Chrome 66-এ এসেছে এবং Firefox-এ প্রয়োগ করা হচ্ছে। এজ সমর্থনের লক্ষণ দেখিয়েছে, কিন্তু এখনও এটি তাদের প্ল্যাটফর্ম ড্যাশবোর্ডে যোগ করতে পারেনি।

বৈশিষ্ট্য সনাক্তকরণের জন্য, আপনি CSS.* সংখ্যাসূচক কারখানা সংজ্ঞায়িত করা হয়েছে:

if (window.CSS && CSS.number) {
  // Supports CSS Typed OM.
}

এপিআই বেসিক

শৈলী অ্যাক্সেস

মানগুলি CSS টাইপড OM-এর ইউনিট থেকে আলাদা। একটি স্টাইল পাওয়া একটি value এবং unit ধারণকারী একটি CSSUnitValue প্রদান করে:

el.attributeStyleMap.set('margin-top', CSS.px(10));
// el.attributeStyleMap.set('margin-top', '10px'); // string arg also works.
el.attributeStyleMap.get('margin-top').value  // 10
el.attributeStyleMap.get('margin-top').unit // 'px'

// Use CSSKeyWorldValue for plain text values:
el.attributeStyleMap.set('display', new CSSKeywordValue('initial'));
el.attributeStyleMap.get('display').value // 'initial'
el.attributeStyleMap.get('display').unit // undefined

গণনা করা শৈলী

কম্পিউটেড শৈলীগুলি window একটি API থেকে HTMLElement , computedStyleMap() এ একটি নতুন পদ্ধতিতে সরানো হয়েছে:

পুরানো CSSOM

el.style.opacity = 0.5;
window.getComputedStyle(el).opacity === "0.5" // Ugh, more strings!

নতুন টাইপ করা OM

el.attributeStyleMap.set('opacity', 0.5);
el.computedStyleMap().get('opacity').value // 0.5

মান ক্ল্যাম্পিং / রাউন্ডিং

নতুন অবজেক্ট মডেলের চমৎকার বৈশিষ্ট্যগুলির মধ্যে একটি হল স্বয়ংক্রিয় ক্ল্যাম্পিং এবং/অথবা গণনা করা শৈলী মানগুলির রাউন্ডিং । একটি উদাহরণ হিসাবে, ধরা যাক আপনি গ্রহণযোগ্য পরিসরের বাইরে একটি মান opacity সেট করার চেষ্টা করেন, [0, 1]। শৈলী গণনা করার সময় টাইপ করা OM মানটিকে 1 এ ক্ল্যাম্প করে:

el.attributeStyleMap.set('opacity', 3);
el.attributeStyleMap.get('opacity').value === 3  // val not clamped.
el.computedStyleMap().get('opacity').value === 1 // computed style clamps value.

একইভাবে, z-index:15.4 রাউন্ড 15 এ সেট করা যাতে মানটি একটি পূর্ণসংখ্যা থাকে।

el.attributeStyleMap.set('z-index', CSS.number(15.4));
el.attributeStyleMap.get('z-index').value  === 15.4 // val not rounded.
el.computedStyleMap().get('z-index').value === 15   // computed style is rounded.

CSS সংখ্যাসূচক মান

টাইপ করা OM-এ সংখ্যা দুটি ধরনের CSSNumericValue অবজেক্ট দ্বারা প্রতিনিধিত্ব করা হয়:

  1. CSSUnitValue - যে মানগুলিতে একটি একক প্রকার রয়েছে (যেমন "42px" )।
  2. CSSMathValue - যে মানগুলিতে একাধিক মান/ইউনিট থাকে যেমন গাণিতিক অভিব্যক্তি (যেমন "calc(56em + 10%)" )।

একক মান

সরল সংখ্যাসূচক মান ( "50%" ) CSSUnitValue অবজেক্ট দ্বারা উপস্থাপিত হয়। যদিও আপনি এই বস্তুগুলি সরাসরি তৈরি করতে পারেন ( new CSSUnitValue(10, 'px') ), বেশিরভাগ সময় আপনি CSS.* ফ্যাক্টরি পদ্ধতি:

const {value, unit} = CSS.number('10');
// value === 10, unit === 'number'

const {value, unit} = CSS.px(42);
// value === 42, unit === 'px'

const {value, unit} = CSS.vw('100');
// value === 100, unit === 'vw'

const {value, unit} = CSS.percent('10');
// value === 10, unit === 'percent'

const {value, unit} = CSS.deg(45);
// value === 45, unit === 'deg'

const {value, unit} = CSS.ms(300);
// value === 300, unit === 'ms'

CSS.* পদ্ধতির সম্পূর্ণ তালিকার জন্য বিশেষত্ব দেখুন।

গণিত মান

CSSMathValue অবজেক্টগুলি গাণিতিক অভিব্যক্তি উপস্থাপন করে এবং সাধারণত একাধিক মান/ইউনিট ধারণ করে। সাধারণ উদাহরণ হল একটি CSS calc() এক্সপ্রেশন তৈরি করা, কিন্তু সমস্ত CSS ফাংশনের জন্য পদ্ধতি রয়েছে: calc() , min() , max()

new CSSMathSum(CSS.vw(100), CSS.px(-10)).toString(); // "calc(100vw + -10px)"

new CSSMathNegate(CSS.px(42)).toString() // "calc(-42px)"

new CSSMathInvert(CSS.s(10)).toString() // "calc(1 / 10s)"

new CSSMathProduct(CSS.deg(90), CSS.number(Math.PI/180)).toString();
// "calc(90deg * 0.0174533)"

new CSSMathMin(CSS.percent(80), CSS.px(12)).toString(); // "min(80%, 12px)"

new CSSMathMax(CSS.percent(80), CSS.px(12)).toString(); // "max(80%, 12px)"

নেস্টেড এক্সপ্রেশন

আরও জটিল মান তৈরি করতে গণিত ফাংশন ব্যবহার করা একটু বিভ্রান্তিকর হয়ে ওঠে। আপনাকে শুরু করার জন্য নীচে কয়েকটি উদাহরণ দেওয়া হল। আমি তাদের পড়া সহজ করার জন্য অতিরিক্ত ইন্ডেন্টেশন যোগ করেছি।

calc(1px - 2 * 3em) এভাবে তৈরি করা হবে:

new CSSMathSum(
  CSS.px(1),
  new CSSMathNegate(
    new CSSMathProduct(2, CSS.em(3))
  )
);

calc(1px + 2px + 3px) এভাবে তৈরি করা হবে:

new CSSMathSum(CSS.px(1), CSS.px(2), CSS.px(3));

calc(calc(1px + 2px) + 3px) এভাবে তৈরি করা হবে:

new CSSMathSum(
  new CSSMathSum(CSS.px(1), CSS.px(2)),
  CSS.px(3)
);

গাণিতিক অপারেশন

CSS Typed OM-এর সবচেয়ে দরকারী বৈশিষ্ট্যগুলির মধ্যে একটি হল আপনি CSSUnitValue অবজেক্টে গাণিতিক ক্রিয়াকলাপ সম্পাদন করতে পারেন।

মৌলিক অপারেশন

বেসিক অপারেশনগুলি ( add / sub / mul / div / min / max ) সমর্থিত:

CSS.deg(45).mul(2) // {value: 90, unit: "deg"}

CSS.percent(50).max(CSS.vw(50)).toString() // "max(50%, 50vw)"

// Can Pass CSSUnitValue:
CSS.px(1).add(CSS.px(2)) // {value: 3, unit: "px"}

// multiple values:
CSS.s(1).sub(CSS.ms(200), CSS.ms(300)).toString() // "calc(1s + -200ms + -300ms)"

// or pass a `CSSMathSum`:
const sum = new CSSMathSum(CSS.percent(100), CSS.px(20)));
CSS.vw(100).add(sum).toString() // "calc(100vw + (100% + 20px))"

পরিবর্তন

পরম দৈর্ঘ্যের একককে অন্য একক দৈর্ঘ্যে রূপান্তর করা যেতে পারে:

// Convert px to other absolute/physical lengths.
el.attributeStyleMap.set('width', '500px');
const width = el.attributeStyleMap.get('width');
width.to('mm'); // CSSUnitValue {value: 132.29166666666669, unit: "mm"}
width.to('cm'); // CSSUnitValue {value: 13.229166666666668, unit: "cm"}
width.to('in'); // CSSUnitValue {value: 5.208333333333333, unit: "in"}

CSS.deg(200).to('rad').value // 3.49066...
CSS.s(2).to('ms').value // 2000

সমতা

const width = CSS.px(200);
CSS.px(200).equals(width) // true

const rads = CSS.deg(180).to('rad');
CSS.deg(180).equals(rads.to('deg')) // true

CSS মান রূপান্তর

CSS রূপান্তরগুলি একটি CSSTransformValue দিয়ে তৈরি করা হয় এবং রূপান্তর মানগুলির একটি অ্যারে পাস করে (যেমন CSSRotate , CSScale , CSSSkew , CSSSkewX , CSSSkewY )। একটি উদাহরণ হিসাবে, বলুন আপনি এই CSS পুনরায় তৈরি করতে চান:

transform: rotateZ(45deg) scale(0.5) translate3d(10px,10px,10px);

টাইপ করা OM এ অনুবাদ করা হয়েছে:

const transform =  new CSSTransformValue([
  new CSSRotate(CSS.deg(45)),
  new CSSScale(CSS.number(0.5), CSS.number(0.5)),
  new CSSTranslate(CSS.px(10), CSS.px(10), CSS.px(10))
]);

এর ভার্বোসিটি (lolz!) ছাড়াও CSSTransformValue কিছু দুর্দান্ত বৈশিষ্ট্য রয়েছে। এটিতে 2D এবং 3D রূপান্তরগুলিকে আলাদা করার জন্য একটি বুলিয়ান সম্পত্তি এবং একটি .toMatrix() পদ্ধতি একটি রূপান্তরের DOMMatrix উপস্থাপনা ফেরত দেয়:

new CSSTranslate(CSS.px(10), CSS.px(10)).is2D // true
new CSSTranslate(CSS.px(10), CSS.px(10), CSS.px(10)).is2D // false
new CSSTranslate(CSS.px(10), CSS.px(10)).toMatrix() // DOMMatrix

উদাহরণ: একটি ঘনক্ষেত্র অ্যানিমেটিং

আসুন রূপান্তর ব্যবহার করার একটি বাস্তব উদাহরণ দেখি। আমরা একটি কিউবকে অ্যানিমেট করতে জাভাস্ক্রিপ্ট এবং সিএসএস রূপান্তর ব্যবহার করব।

const rotate = new CSSRotate(0, 0, 1, CSS.deg(0));
const transform = new CSSTransformValue([rotate]);

const box = document.querySelector('#box');
box.attributeStyleMap.set('transform', transform);

(function draw() {
  requestAnimationFrame(draw);
  transform[0].angle.value += 5; // Update the transform's angle.
  // rotate.angle.value += 5; // Or, update the CSSRotate object directly.
  box.attributeStyleMap.set('transform', transform); // commit it.
})();

লক্ষ্য করুন:

  1. সংখ্যাসূচক মান মানে আমরা সরাসরি গণিত ব্যবহার করে কোণ বৃদ্ধি করতে পারি!
  2. DOM স্পর্শ করা বা প্রতিটি ফ্রেমে একটি মান পড়ার পরিবর্তে (যেমন no box.style.transform=`rotate(0,0,1,${newAngle}deg)` ), অন্তর্নিহিত CSSTransformValue ডেটা আপডেট করার মাধ্যমে অ্যানিমেশন চালিত হয় বস্তু, কর্মক্ষমতা উন্নত

ডেমো

নীচে, আপনি একটি লাল ঘনক দেখতে পাবেন যদি আপনার ব্রাউজার Typed OM সমর্থন করে। আপনি যখন এটির উপর মাউস করেন তখন ঘনক্ষেত্রটি ঘোরানো শুরু হয়। অ্যানিমেশন CSS টাইপড OM দ্বারা চালিত হয়! 🤘

CSS কাস্টম বৈশিষ্ট্য মান

CSS var() টাইপ করা OM-এ একটি CSSVariableReferenceValue অবজেক্টে পরিণত হয়। তাদের মানগুলি CSSUnparsedValue এ পার্স করা হয় কারণ তারা যে কোনও প্রকার (px, %, em, rgba(), ইত্যাদি নিতে পারে।

const foo = new CSSVariableReferenceValue('--foo');
// foo.variable === '--foo'

// Fallback values:
const padding = new CSSVariableReferenceValue(
    '--default-padding', new CSSUnparsedValue(['8px']));
// padding.variable === '--default-padding'
// padding.fallback instanceof CSSUnparsedValue === true
// padding.fallback[0] === '8px'

আপনি যদি একটি কাস্টম সম্পত্তির মান পেতে চান তবে কিছু কাজ করতে হবে:

<style>
  body {
    --foo: 10px;
  }
</style>
<script>
  const styles = document.querySelector('style');
  const foo = styles.sheet.cssRules[0].styleMap.get('--foo').trim();
  console.log(CSSNumericValue.parse(foo).value); // 10
</script>

অবস্থানের মান

CSS বৈশিষ্ট্যগুলি যেগুলি স্থান-বিচ্ছিন্ন x/y অবস্থান নেয় যেমন object-position CSSPositionValue অবজেক্ট দ্বারা উপস্থাপিত হয়।

const position = new CSSPositionValue(CSS.px(5), CSS.px(10));
el.attributeStyleMap.set('object-position', position);

console.log(position.x.value, position.y.value);
// → 5, 10

পার্সিং মান

টাইপ করা OM ওয়েব প্ল্যাটফর্মে পার্সিং পদ্ধতি চালু করে! এর মানে হল আপনি এটি ব্যবহার করার চেষ্টা করার আগে শেষ পর্যন্ত প্রোগ্রাম্যাটিকভাবে CSS মান পার্স করতে পারেন! এই নতুন ক্ষমতা প্রাথমিক বাগ এবং বিকৃত CSS ধরার জন্য একটি সম্ভাব্য জীবন রক্ষাকারী।

একটি সম্পূর্ণ শৈলী পার্স করুন:

const css = CSSStyleValue.parse(
    'transform', 'translate3d(10px,10px,0) scale(0.5)');
// → css instanceof CSSTransformValue === true
// → css.toString() === 'translate3d(10px, 10px, 0) scale(0.5)'

CSSUnitValue তে মান পার্স করুন:

CSSNumericValue.parse('42.0px') // {value: 42, unit: 'px'}

// But it's easier to use the factory functions:
CSS.px(42.0) // '42px'

ত্রুটি পরিচালনা

উদাহরণ - সিএসএস পার্সার এই transform মানটির সাথে খুশি হবে কিনা তা পরীক্ষা করুন:

try {
  const css = CSSStyleValue.parse('transform', 'translate4d(bogus value)');
  // use css
} catch (err) {
  console.err(err);
}

উপসংহার

অবশেষে CSS-এর জন্য একটি আপডেট করা অবজেক্ট মডেল পাওয়া ভালো। স্ট্রিংগুলির সাথে কাজ করা আমার কাছে কখনই সঠিক মনে হয়নি। CSS টাইপ করা OM API কিছুটা ভার্বোস, কিন্তু আশা করি এর ফলে কম বাগ এবং লাইনের নিচে আরও বেশি পারফরম্যান্স কোড আসে।