নতুন 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 ব্যবহার করার পরিবর্তে, আপনি elements এর জন্য একটি নতুন .attributeStyleMap প্রপার্টি এবং স্টাইলশিট নিয়মের জন্য একটি .styleMap প্রপার্টির মাধ্যমে styles অ্যাক্সেস করবেন। উভয়ই একটি 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 গুলি Map-এর মতো বস্তু, তাই তারা সমস্ত সাধারণ সন্দেহভাজনদের (get/set/keys/value/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 string ( '0.3' ) তে সেট করা আছে কিন্তু যখন সম্পত্তিটি পরে পড়া হয় তখন একটি সংখ্যা ফিরে আসে।

সুবিধা

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

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

  • কম বাগ । যেমন সংখ্যাসূচক মান সবসময় সংখ্যা হিসেবে ফেরত পাঠানো হয়, স্ট্রিং হিসেবে নয়।

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

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

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

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

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

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

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

বৈশিষ্ট্য সনাক্তকরণের জন্য, আপনি CSS.* সংখ্যাসূচক কারখানাগুলির মধ্যে একটি সংজ্ঞায়িত কিনা তা পরীক্ষা করতে পারেন:

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

এপিআই বেসিকস

স্টাইল অ্যাক্সেস করা হচ্ছে

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

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.

সিএসএস সংখ্যাসূচক মান

টাইপ করা 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 টাইপড 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 ট্রান্সফর্মগুলি 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))
]);

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

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 ডেটা অবজেক্ট আপডেট করে পরিচালিত হয়, কর্মক্ষমতা উন্নত করে

ডেমো

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

CSS কাস্টম প্রোপার্টি মান

টাইপ করা OM-এ CSS var() একটি 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

মান বিশ্লেষণ করা হচ্ছে

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

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

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'

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

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

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

উপসংহার

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