سهبعدی واقعی با CSS: از پرسپکتیو تا ساخت یه صحنه
خلاصهٔ کاملتر
کارمن آنسیو این مقاله رو با یه مقایسه شروع میکنه: Super Mario Bros 3 عمق داشت ولی همهش نقاشی بود، لایههای تختی که فقط با سرعتهای مختلف حرکت میکردن؛ در حالی که Super Mario 64 از ثانیهٔ اول یه فضای واقعی بود و دوربینش هم دست خودت بود. به گفتهٔ نویسنده، همین فاصله رو با CSS هم میشه طی کرد و این فاصله از چیزی که به نظر میرسه کوتاهتره.
عمق تخت با دو ترفند ساخته میشه: چیزهای دورتر پشتتر کشیده میشن و موقع جابهجایی نما کمتر تکون میخورن، یعنی همون parallax آشنا. ولی این کار یه سقف داره: هر لایه هنوز یه تصویر تخته که مستقیم روبهروی توئه، پس تا بخوای صحنه رو بچرخونی یا یه بلوک رو از پهلو ببینی، توهم میشکنه.
اینجاست که perspective وارد میشه. این پراپرتی روی خودِ المانی که میچرخه نمیشینه، روی والد یعنی صحنه میشینه، و مقدارش فاصلهٔ چشم تا صفحهست: عدد کوچیک یعنی صورتت چسبیده به شیشه و لبههای نزدیک بزرگ میشن، عدد بزرگ یعنی لنز تله از اون سر اتاق و صحنه تقریباً تخت. نویسنده برای کار رابط کاربری بین ۸۰۰ تا ۱۲۰۰ پیکسل رو پیشنهاد میده و فقط وقتی حالت فیشآی میخواد میره زیر ۴۰۰. نصف دیگهٔ دوربین هم perspective-origin ـه که میگه دوربین کجا ایستاده.
.scene {
perspective: 700px; /* how close the camera is */
perspective-origin: 50% 44%; /* where the camera stands */
}پراپرتیای که واقعاً صحنه رو از نقاشی جدا میکنه transform-style: preserve-3d ـه. مرورگر بهصورت پیشفرض هر المان سهبعدی رو موقع رسم روی صفحهٔ والدش تخت میکنه، پس بچههاش دیگه عمق واقعی ندارن. نکتهٔ دردسرساز اینه که این خاصیت فقط تا جایی جلو میره که زنجیرهٔ والدها بدون وقفه preserve-3d داشته باشن؛ یه والد تخت وسط مسیر، هرچی زیرشه رو له میکنه. نویسنده میگه وقتی صحنه بیدلیل تخت رندر شد، اول همین زنجیره رو چک کن.
بلوک ساختمانی همیشگی هم یه cuboid ـه: شش وجه تخت که هر کدوم به بیرون چرخیده و به اندازهٔ نصف عمق هل داده شده. بهجای عدد ثابت، سه متغیر --w و --h و --d اندازه رو تعیین میکنن تا یه دستور واحد هم جعبه بده هم لولهٔ بلند. ترتیب transformها هم مهمه: rotateY(90deg) translateZ(60px) اول وجه رو میچرخونه بعد توی جهت جدید خودش هلش میده، و اگه جاشون رو عوض کنی جای دیگهای درمیاد.
.block { --w: 130px; --h: 130px; --d: 130px; transform-style: preserve-3d; }
.front { width: var(--w); height: var(--h);
transform: translate(-50%,-50%) translateZ(calc(var(--d) / 2)); }
.right { width: var(--d); height: var(--h);
transform: translate(-50%,-50%) rotateY(90deg) translateZ(calc(var(--w) / 2)); }نکات کلیدی:
- perspective و perspective-origin هر دو روی والد (صحنه) میشینن، نه روی المانی که میچرخه.
- نویسنده برای رابط کاربری perspective بین ۸۰۰ تا ۱۲۰۰ پیکسل رو پیشنهاد میده؛ زیر ۴۰۰ حالت فیشآی میده.
- transform-style: preserve-3d فقط در زنجیرهٔ بیوقفهٔ والدها کار میکنه؛ یه والد flat همهچی رو تخت میکنه.
- backface-visibility: hidden جلوی دیدهشدن وجههای پشتی رو موقع چرخش میگیره و transform-origin محور چرخش رو جابهجا میکنه.
- توابع داخل transform از چپ به راست اعمال میشن، پس جابهجا کردنشون نتیجه رو کاملاً عوض میکنه.




