డెవలపర్లు త్వరగా సాధించే విజయాలను ఇష్టపడతారు. "డార్క్ మోడ్ జోడించండి" అని టికెట్ వచ్చినప్పుడు, సులభమైన మార్గం స్పష్టంగా కనిపిస్తుంది: light.css రాయండి, dark.css రాయండి, మరియు వాటి మధ్య టోగుల్ చేయండి. ఇది శుభ్రంగా అనిపిస్తుంది. వేగంగా పూర్తవుతుంది. మూడు కాంపోనెంట్స్ ఉన్న చిన్న సైడ్ ప్రాజెక్ట్‌కు ఇది సరిపోవచ్చు. కానీ మీ అప్లికేషన్ కొన్ని మోడ్యూల్స్ దాటి పెరిగినప్పుడు, ఆ రెండో ఫైల్ ఒక ఆస్తిగా కాకుండా, మీరు డూప్లికేట్‌గా నిర్వహించాల్సిన ఒక భారంగా మారుతుంది.

రెండు-ఫైళ్ల ఉచ్చు (The Two-File Trap)

మొదటి చూపులో ఈ లాజిక్ సరైనదే అనిపిస్తుంది. బాధ్యతల విభజన (Separation of concerns), అవునా? లైట్ అంశాలు ఇక్కడ, డార్క్ అంశాలు అక్కడ. మీరు మీ ఎడిటర్‌లో రెండు బఫర్‌లను ఓపెన్ చేస్తారు. లైట్ ఫైల్ నుండి కార్డ్ స్టైల్స్‌ను డార్క్ ఫైల్‌లోకి కాపీ చేస్తారు, #ffffff స్థానంలో #1a1a1a మారుస్తారు, మరియు పని ముగిస్తారు.

సమస్య మొదటి వారంలో ఉండదు. సమస్య ఆరో నెలలో వస్తుంది, అప్పుడు ఒక డిజైనర్ ప్రైమరీ బటన్‌పై కొంచెం భిన్నమైన బోర్డర్ రేడియస్ కావాలని అడిగినప్పుడు, లేదా ప్రొడక్ట్ టీమ్ చెకౌట్ ఫామ్‌పై కొత్త వార్నింగ్ స్టేట్‌ను కోరినప్పుడు వస్తుంది. మీరు లైట్ స్టైల్‌షీట్‌ను అప్‌డేట్ చేస్తారు. డార్క్ స్టైల్‌షీట్‌ను కేవలం ఒక చూపు చూస్తారు. బహుశా ఆ మార్పును కాపీ చేయడం మీకు గుర్తుకు రావచ్చు. లేదా గుర్తుకు రాకపోవచ్చు. ఆ తేడాలోనే నాణ్యత దెబ్బతింటుంది. మీరు ఇకపై ఒక ఇంటర్‌ఫేస్‌ను మాత్రమే నిర్వహించడం లేదు. మీరు ఒకే HTML స్కెలిటన్‌ను పంచుకుంటున్న రెండు సమాంతర ఇంటర్‌ఫేస్‌లను నిర్వహిస్తున్నారు.

థీమ్ డ్రిఫ్ట్ అనివార్యం (Theme Drift Is Inevitable)

ఈ తేడాకు ఫ్రంటెండ్ టీమ్‌లు గుర్తించడం ప్రారంభించిన ఒక పేరు ఉంది: థీమ్ డ్రిఫ్ట్ (theme drift). మీ రెండు స్టైల్‌షీట్‌లు వేర్వేరు వేగంతో అభివృద్ధి చెందినప్పుడు ఇది జరుగుతుంది. ఇక్కడ ఒక ప్యాడింగ్ అడ్జస్ట్‌మెంట్. అక్కడ ఒక షాడో టవీక్. డార్క్ ఫైల్ నిర్లక్ష్యం చేయబడిన తోబుట్టువులా మారుతుంది. లేదా ఇంకా దారుణంగా, అది భయానికి కారణమవుతుంది. డెవలపర్లు మార్పులను నివారించడం ప్రారంభిస్తారు, ఎందుకంటే ఒక థీమ్‌ను తాకడం అంటే మరొక ఫైల్‌లో వెతికి ఆ పనిని డూప్లికేట్ చేయాల్సి వస్తుంది.

దీని వల్ల కలిగే మానసిక శ్రమ (cognitive overhead) వేగంగా పెరుగుతుంది. మీరు CSSని ఒక్కసారి మాత్రమే రాయాలనుకున్నారు. దానికి బదులుగా మీరు దానిని రెండుసార్లు రాశారు, మరియు ఇప్పుడు డిజైన్ సిస్టమ్ మారిన ప్రతిసారీ మీరు ఆ అప్పుపై వడ్డీ చెల్లిస్తున్నారు. లైట్ ఫైల్‌లో ఎవరో ఒక ఫ్లెక్స్ గ్యాప్‌ను అప్‌డేట్ చేసి, దానిని డార్క్ ఫైల్‌లో మర్చిపోవడం వల్ల డార్క్ మోడ్‌లో ఐకాన్లు సరిగ్గా ఉండవు. కొత్త యాక్సెసిబిలిటీ రూల్ కేవలం ఒక షీట్‌లో మాత్రమే చేరినందున ఫోకస్ రింగ్‌లు కనిపించవు. UI కేవలం తప్పుగా కనిపించడమే కాదు, అది విరిగిపోయినట్లు అనిపిస్తుంది.

సెమాంటిక్ టోకెన్లను ఉపయోగించండి (Use Semantic Tokens)

దీనికి పరిష్కారం మెరుగైన డిఫ్ టూల్ (diff tool) లేదా కఠినమైన కోడ్ రివ్యూ కాదు. పరిష్కారం రంగుల గురించి ఆలోచించే విధానాన్ని మార్చుకోవడం. మీ స్టైల్స్‌ను కేవలం అవి ఎలా కనిపిస్తాయి అనే దాని ఆధారంగా కాకుండా, వాటి ఉద్దేశ్యం (purpose) ఆధారంగా నిర్వహించడం ప్రారంభించండి. ఇక్కడే సెమాంటిక్ టోకెన్లు (semantic tokens) ఉపయోగపడతాయి.

ఒక కార్డ్‌కు వైట్ బ్యాక్‌గ్రౌండ్ కేటాయించడానికి బదులుగా, దానికి ఒక 'సర్ఫేస్ బ్యాక్‌గ్రౌండ్' (surface background) కేటాయించండి. టెక్స్ట్ కోసం బ్లాక్ మరియు ఆఫ్-వైట్ మధ్య ఎంచుకోవడానికి బదులుగా, ఒక 'టెక్స్ట్ కలర్'ను ఎంచుకోండి. యూజర్ లైట్ మోడ్‌ను ఇష్టపడుతున్నారా లేదా డార్క్ మోడ్‌ను ఇష్టపడుతున్నారా అనేది ఆ కాంపోనెంట్‌కు తెలియదు లేదా దానితో సంబంధం లేదు. అది కేవలం తన పనికి సరిపోయే టోకెన్‌ను మాత్రమే అడుగుతుంది.

ఒక స్టాండర్డ్ బటన్ గురించి ఆలోచించండి. రెండు-ఫైళ్ల ప్రపంచంలో, .btn అనేది వైట్ బ్యాక్‌గ్రౌండ్ మరియు డార్క్ బోర్డర్‌తో లైట్ స్టైల్‌షీట్‌లో ఉంటుంది. దాని కవల (twin) డార్క్ స్టైల్‌షీట్‌లో నలుపుకు దగ్గరగా ఉండే బ్యాక్‌గ్రౌండ్ మరియు లైట్ బోర్డర్‌తో ఉంటుంది. అంటే ఒక బటన్ కోసం రెండు రెట్లు కోడ్. టోకెన్లతో, .btn కి ఒకే డిక్లరేషన్ ఉంటుంది: బ్యాక్‌గ్రౌండ్ var(--color-surface-secondary) మరియు బోర్డర్ var(--color-border-default). ఈ విలువలు (values) రూట్ (root) వద్ద ఉంటాయి. సైట్ లైట్ మోడ్‌లో ఉన్నప్పుడు, --color-surface-secondary అనేది #f8f9fa వంటి విలువకు మారుతుంది. డార్క్ మోడ్‌లో, అదే టోకెన్ #2d2d2d కి మారుతుంది. బటన్ కాంపోనెంట్ ఎప్పుడూ మారదు. దాని కింద ఉన్న డేటా మాత్రమే మారుతుంది.

స్ట్రక్చర్ మరియు డేటా మధ్య ఉన్న ఈ తేడా సూక్ష్మంగా ఉన్నప్పటికీ శక్తివంతమైనది. మీ కార్డ్ కాంపోనెంట్ లేఅవుట్, స్పేసింగ్, టైపోగ్రఫీ మరియు ఎలివేషన్‌ను ఒక్కసారి నిర్వచిస్తుంది. మీ థీమ్ లేయర్ కలర్ ప్యాలెట్‌ను నిర్వచిస్తుంది. CSS కస్టమ్ ప్రాపర్టీస్ (custom properties) సరిగ్గా ఇందుకోసమే నిర్మించబడ్డాయి.

ఆర్కిటెక్చర్ ఎలా మారుతుంది (How the Architecture Changes)

ఈ విధానం మీరు స్టైల్స్‌ను రాసే విధానాన్ని ప్రాథమికంగా మారుస్తుంది.

పాత పద్ధతి సాధారణంగా ఇలా ఉంటుంది:

  • ప్యాడింగ్, రేడియస్, బ్యాక్‌గ్రౌండ్, టెక్స్ట్ కలర్ మరియు షాడోను నిర్వచించే ఒక లైట్ కార్డ్ స్టైల్‌షీట్.
  • రంగులను మార్చడానికి మాత్రమే దాదాపు అన్ని ప్రాపర్టీలను మళ్ళీ నిర్వచించే ఒక డార్క్ కార్డ్ స్టైల్‌షీట్.
  • ఏ స్టైల్‌షీట్‌ను లోడ్ చేయాలి లేదా బాడీపై ఏ క్లాస్‌ను టోగుల్ చేయాలి అని నిర్ణయించే ఒక లాజిక్ లేయర్.

కొత్త పద్ధతి ఇలా ఉంటుంది:

  • లేఅవుట్‌ను నిర్వచించి మరియు సెమాంటిక్ టోకెన్లను కేటాయించే ఒకే ఒక కార్డ్ స్టైల్‌షీట్.
  • లైట్ కాంటెక్స్ట్‌లో ఆ టోకెన్ల అర్థం ఏమిటో నిర్వచించే ఒక థీమ్ ఫైల్.
  • డార్క్ కాంటెక్స్ట్‌లో ఆ టోకెన్ల అర్థం ఏమిటో నిర్వచించే ఒక థీమ్ ఫైల్, లేదా అదే ఫైల్‌లో ఒక బ్లాక్.
  • కాంపోనెంట్ లేయర్‌ను తాకకుండానే వాల్యూ లేయర్‌ను మార్చే ఒకే ఒక అట్రిబ్యూట్ స్వాప్.

మీరు సెటప్‌ను స్థిరంగా ఉంచుతారు. మీరు కేవలం డేటాను మాత్రమే మారుస్తారు. డిజైనర్ మూడవ థీమ్‌ను, బహుశా హై-కాంట్రాస్ట్ మోడ్ లేదా మిడ్‌నైట్ బ్లూ వేరియంట్‌ను పరిచయం చేయాలనుకున్నప్పుడు, మీరు కార్డ్‌ను మళ్ళీ రాయాల్సిన అవసరం లేదు. మీరు టోకెన్ మ్యాప్‌కు మరొక అసైన్‌మెంట్‌ను జోడిస్తే సరిపోతుంది. కాంపోనెంట్ ఏమీ తెలియని దానిలా (dumb) సంతోషంగా ఉంటుంది. దానికి ఇంకా ఒక సర్ఫేస్ కలర్ (surface color) కావాలి. ఏ సర్ఫేస్ కలర్ వాడాలో థీమ్ దానికి చెబుతుంది.

డేటా ఆట్రిబ్యూట్ స్విచ్ (The Data Attribute Switch)

ఇంప్లిమెంటేషన్ (Implementation) సరళంగా మరియు చదవడానికి వీలుగా ఉంటుంది. మీ HTML ట్యాగ్‌కు data-theme="dark" వంటి డేటా ఆట్రిబ్యూట్‌ను వర్తింపజేయండి, మరియు మీ టోకెన్ నిర్వచనాలను (token definitions) దాని కింద స్కోప్ చేయండి.

జావాస్క్రిప్ట్ (JavaScript) రన్ అవ్వకముందే పేజీ సరిగ్గా రెండర్ అవ్వడానికి, లైట్ ఎక్స్‌పీరియన్స్ కోసం :root లో మీ డిఫాల్ట్‌లను సెట్ చేయండి. ఆపై [data-theme="dark"] కింద టోకెన్ విలువలను ఓవర్‌రైడ్ (override) చేయండి. ఒక చిన్న స్క్రిప్ట్ టోగుల్ క్లిక్‌ను గమనిస్తుంది, ఆట్రిబ్యూట్‌ను అప్‌డేట్ చేస్తుంది, మరియు పేజీలోని ప్రతి కాంపోనెంట్ వెంటనే స్పందిస్తుంది. ఒక్కో ఎలిమెంట్‌పై క్లాస్ త్రాషింగ్ (class thrashing) అవసరం లేదు. రెండరింగ్ మధ్యలో పూర్తిగా వేరే స్టైల్‌షీట్‌ను ఇంపోర్ట్ చేయాల్సిన అవసరం లేదు. బ్రౌజర్‌కు ఇప్పటికే వేరియబుల్స్ మెమరీలో ఉంటాయి; అది కేవలం కొత్త విలువలతో రీపెయింట్ (repaint) చేస్తుంది.

ఇది మీ కోడ్‌ను చాలా ఆచరణాత్మకమైన రీతిలో క్లీన్‌గా ఉంచుతుంది. .card యొక్క ప్రతి ఇన్‌స్టెన్స్‌ను కనుగొనడానికి మీరు రెండు డైరెక్టరీల అంతటా grep చేయాల్సిన అవసరం లేదు. ఒకే నోడ్‌పై పేరుకుపోతున్న పోటీ థీమ్ క్లాస్‌ల మధ్య స్పెసిఫిసిటీ వార్స్ (specificity wars) గురించి మీరు ఆందోళన చెందాల్సిన అవసరం లేదు. మీ HTML చదవడానికి వీలుగా ఉంటుంది. మీ CSS సెంట్రలైజ్డ్ (centralized) గా మరియు సెర్చ్ చేయదగినదిగా ఉంటుంది.

ఇది విలువలకు సంబంధించినది, వెర్షన్లకు కాదు

డార్క్ మోడ్ అనేది విలువలకు (values) సంబంధించినది. ఇది మీ UI యొక్క రెండవ వెర్షన్ కాదు. రాత్రిపూట మీ కార్డ్ మూలలు (corners) మరింత గుండ్రంగా మారవు. మీ గ్రిడ్ (grid) వేరే ఆకారంలోకి కుంచించుకుపోదు. మీ టైప్ స్కేల్‌కు (type scale) కొత్త రిథమ్ అవసరం లేదు. కేవలం రంగులు మారుతాయి, మరియు కొన్నిసార్లు షాడోస్ (shadows) కొంచెం లోతుగా కనిపిస్తాయి. డార్క్‌నెస్‌ను పూర్తి రీస్కిన్ (reskin) గా పరిగణించడం అనేది మెయింటెనెన్స్ సమస్యలను సృష్టించే ఓవర్-ఇంజనీరింగ్ (over-engineering).

దీనిని సరిగ్గా అర్థం చేసుకున్న టీమ్‌లు తమ డిజైన్ సిస్టమ్‌ను ఒక డేటాబేస్‌లా పరిగణిస్తారు. కాంపోనెంట్లు పేరు ద్వారా ప్రాపర్టీల కోసం క్వరీ (query) చేస్తాయి. థీమ్‌లు రికార్డులను అందిస్తాయి. లైట్ నుండి డార్క్‌కి మారడం అనేది ఒక క్వరీ పారామీటర్ మార్పు మాత్రమే, స్కీమా రీరైట్ (schema rewrite) కాదు.

ఆ ఆలోచనా విధానమే మిమ్మల్ని థీమ్ డ్రిఫ్ట్ (theme drift) నుండి కాపాడుతుంది. ఒకే కార్డ్. ఒకే బటన్. స్పేసింగ్ మరియు సైజింగ్ కోసం ఒకే సోర్స్ ఆఫ్ ట్రూత్ (source of truth). ప్యాలెట్ (palette) ఒకే చోట ఉంటుంది, లాజికల్‌గా మ్యాప్ చేయబడి, యూజర్ కోరుకునే ఏ వాతావరణానికైనా సిద్ధంగా ఉంటుంది.

అసలైన సారాంశం (The Real Takeaway)

మీరు లైట్ మరియు డార్క్ కోసం రెండు CSS ఫైళ్లను మెయింటైన్ చేస్తుంటే, మీరు థీమింగ్ చేయడం లేదు. మీరు క్లోనింగ్ (cloning) చేస్తున్నారు. సెమాంటిక్ టోకెన్స్‌కు (semantic tokens) మారండి, వాటిని రూట్-లెవల్ డేటా ఆట్రిబ్యూట్‌తో స్కోప్ చేయండి, మరియు మీ కాంపోనెంట్లు అప్పియరెన్స్‌లను (appearances) హార్డ్‌కోడ్ చేయకుండా రోల్స్ (roles) కోసం అడిగేలా చేయండి. ప్రారంభ రిఫ్యాక్టర్ (refactor) కష్టమైనప్పటికీ, దానికి ప్రత్యామ్నాయం సమాంతర స్టైల్‌షీట్‌ల మధ్య ముగింపు లేని పోరాటంలా ఉంటుంది. ఒకే కార్డ్‌ను రెండుసార్లు రాయడానికి జీవితం చాలా చిన్నది.