عناصر SVG مثل عناصر HTML از یک سیستمی مثل Box Model در CSS تبعیت نمی کنند. که این موضوع مکان دهی و تغییر شکل این عناصر را کمی سخت تر می کند اما زمانی که با سیستم مختصات SVG به خوبی آشنا شویم کار با SVG آسان تر خواهد شد.
در این مطلب به سراغ سه تا از مهمترین ویژگی های SVG به نام های viewBox، viewport و preserveAspectRatio می رویم.
بوم نقاشی SVG
به محیطی که SVG روی آن رسم می شود بوم نقاشی SVG یا SVG Canvas گفته می شود. از لحاظ مفهومی این بوم اندازه بی نهایت دارد اما زمانی که یک مرورگر می خواهد یک طرح SVG را رسم کند این طرح محدود به یک ناحیه خاص و محدود به نام Viewport است و این باعث می شود قسمت هایی از SVG که خارج از این ناحیه قرار دارند بریده شده و نمایش داده نشوند.
Viewport
Viewport ناحیه ای است که در آن SVG قابل مشاهده خواهد بود. می توان Viewport را شبیه به پنجره ای به ذهن آورد که از طریق آن یک منظره قابل مشاهده است. حال سراسر این منظره می تواند از طریق این پنجره قابل دیدن باشد یا فقط قسمتی از آن.
Viewport در مورد SVG نیز مشابه به Viewport مرورگر است. یک صفحه وب می تواند بزرگتر از Viewport باشد و در بیشتر مواقع دراز تر از آن است. به همین دلیل است که در بیشتر مواقع صفحات وب در راستای عمودی اسکرول می شوند و در هر لحظه فقط قسمتی از یک صفحه وب از طریق پنجره ما یا همان Viewport قابل مشاهده است.
اندازه Viewport در SVG توسط ویژگی های width
و height
بر روی عنصر <svg>
تعیین می شود. به عنوان نمونه در مثال زیر اندازه آن برابر با 800 پیکسل در 600 پیکسل خواهد بود:
<svg width="800" height="600">
<!-- SVG content drawn onto the SVG canvas -->
</svg>
این مقادیر را می توان با واحد یا بدون واحد نوشت. زمانی که بدون واحد می نویسیم مرورگر آن ها را به px در نظر می گیرد.
واحدهای دیگر قابل استفاده می توانند em, ex, px, pt, pc, cm, mm, in و یا درصد باشند.
به محض اینکه اندازه Viewport مشخص می شود مرورگر یک سیستم مختصات اولیه viewport و یک سیستم مختصات اولیه کاربری مشخص می کند.
سیستم مختصات اولیه
سیستم مختصات اولیه viewport سیستم مختصاتی است که روی viewport قرار می گیرد با نقطه مبدا واقع در گوشه سمت چپ و بالای viewport، یعنی همان نقطه (0,0) با یک محور مثبت x به سمت راست و یک محور مثبت y به سمت پایین و هر پیکسل روی این محور برابر با یک پیکسل روی viewport می باشد.
این سیستم مختصات مشابه سیستم مختصات عناصر HTML است.
سیستم مختصات اولیه کاربری سیستم مختصاتی است که روی بوم نقاشی SVG قرار می گیرد. این سیستم مختصات هم در حالت اولیه کاملا مشابه سیستم مختصات اولیه viewport است و روی آن قرار می گیرد.
در ادامه خواهیم دید که می توان این سیستم مختصات را توسط ویژگی viewBox
تغییر داد.
فعلا از ویژگی viewBox
استفاده نمی کنیم تا این دو سیستم مختصات روی هم قرار گرفته و کاملا مشابه یکدیگر باشند.
در تصاویر و مثالهایی که در ادامه بررسی می کنیم سیستم مختصات اولیه viewport خاکستری و سیستم مختصات اولیه کاربری آبی خواهند بود.
viewBox
viewBox همان سیستم مختصات کاربری می باشد. از این سیستم مختصات برای رسم SVG برروی بوم نقاشی آن استفاده می شود، همچنین این سیستم مختصات می تواند کوچک تر یا بزرگ تر از سیستم مختصات Viewport باشد که در نتیجه می تواند قسمتی از آن یا سراسر آن از طریق Viewport قابل مشاهده باشد.
در تصویر بالا سیستم مختصات کاربری دقیقا برابر با سیستم مختصات viewport است چرا که ما سیستم مختصات کاربری یا همان viewBox را تعیین نکردیم و مرورگر بصورت خودکار آن را برابر با سیستم مختصات viewport قرار می دهد.
ویژگی viewBox
چهار مقدار را به عنوان پارامتر می پذیرد:
viewBox = <min-x> <min-y> <width> <height>
مقادیر <min-x>
و <min-y>
گوشه سمت چپ بالای viewBox را تعیین می کنند و width
و height
عرض و ارتفاع آن را مشخص می کنند.
توجه داشته باشیم که این مقادیر عرض و ارتفاع می توانند متفاوت از مقادیر عرض و ارتفاع عنصر <svg>
باشند.
مقادیر صفر برای عرض و ارتفاع باعث می شوند تا عنصر SVG رسم نشود. جدا!؟ :)
توجه داشته باشیم که می توان اندازه viewport را در CSS نیز تعیین کرد. مثلا می توان عرض آن را برابر با 100 درصد قرار داد تا بتوان عنصر SVG را به سمت واکنشگرایی سوق داد.
در مثال زیر viewBox دقیقا برابر با مختصات viewport است اما می توانیم آن را به اندازه ای دیگر تغییر دهیم:
<svg width="800" height="600" viewbox="0 0 800 600">
<!-- SVG content drawn onto the SVG canvas -->
</svg>
بهترین راه درک و تشخیص تفاوت viewBox و viewport بررسی مثال هایی در قالب تصویر است. فعلا با مثالهایی شروع می کنیم که aspect ratio یا همان نسبت ابعادی viewBox و viewport با هم برابر باشند، چون اگر نباشند نیاز است تا ویژگی دیگری را به نام preserveAspectRatio
بشناسیم.
نسبت ابعادی viewBox == نسبت ابعادی viewport
در مثال اول ابعاد viewBox را برابر با نصف ابعاد viewport و همینطور مبدا آن را برابر با همان (0,0) قرار می دهیم.
چون عرض و ارتفاع viewBox برابر با نصف عرض و ارتفاع viewport است بدین معنی است که نسبت ابعادی هر دو سیستم مختصات با هم برابر است و ما آن را حفظ کرده ایم.
<svg width="800" height="600" viewbox="0 0 400 300">
<!-- SVG content drawn onto the SVG canvas -->
</svg>
بسیار خوب، حالا viewbox="0 0 400 300"
دقیقا چکار می کند؟
- یک ناحیه خاص را برای بوم نقاشی SVG مشخص می کند که این ناحیه از نقطه
(0,0)
تا نقطه(400,300)
کشیده می شود. - سپس طرح SVG محدود به همان ناحیه برش می خورد.
- این ناحیه Scale یا همان بزرگ می شود بطوری که کل فضای viewport را بگیرد. (شبیه به حالتی که چیزی را با زوم کردن بزرگ می کنیم)
- سیستم مختصات کاربری یا همان viewBox به سیستم مختصات viewport نگاشت می شود در این مثال این یعنی هر واحد viewbox برابر با دو واحد viewport می شود.
چرا دو واحد؟
آفرین… چون ابعاد viewBox نصف ابعاد viewport بود :)
تصویر زیر عملیات نگاشت این viewBox را به مثال ما بیان می کند. یادمان باشد که محورهای خاکستری مربوط به viewport و نسبت های آبی مربوط به viewBox هستند:
از الان به بعد هر چیزی که روی بوم نقاشی SVG رسم شود بر اساس سیستم مختصات جدید خواهد بود.
برای درک بهتر موارد گفته شده می توان مثال Google Map را در ذهن آورد. زمانی که بر روی یک ناحیه خاص نقشه بزرگ نمایی می کنیم آن ناحیه تنها قسمت قابل مشاهده خواهد بود که درون Viewport مرورگر بزرگ نمایی شده و کل فضای آن را گرفته است. اما می دانیم دیگر قسمت های نقشه هنوز وجود دارند ولی قابل مشاهده نیستند چرا که از مرزهای Viewport مرورگر خارج شده اند. یعنی برش خورده اند.
اکنون مقادیر <min-x>
و <min-y>
را به 100 تغییر می دهیم و نسبت ابعادی را هم حفظ می کنیم:
<svg width="800" height="600" viewbox="100 100 200 150">
<!-- SVG content drawn onto the SVG canvas -->
</svg>
تاثیر viewBox="100 100 200 150"
بر روی مثال ما در تصویر زیر به نمایش گذاشته شده است:
با این نگاشت هر واحد viewBox برابر با چهار واحد viewport خواهد بود.
عملیات تغییر اندازه مبدا یک نوع عملیات transform
است و کاملا شبیه به این است که بوم نقاشی SVG را 100 واحد به بالا و 100 واحد به چپ حرکت دهیم (transform="translate(-100 -100)"
)
تنها تفاوت این دو روش در این است که روش transform
روی ویژگی های x
، y
، width
و height
تاثیر می گذارد اما روش تغییر مبدا از طریق viewBox روی این ویژگی های عنصر <svg>
تاثیری نمی گذارد.
برگردیم به همان مثالی که viewBox ابعادی برابر با 300 و 400 واحد داشت. اکنون به جای اعداد مثبت از اعداد منفی برای تعیین مبدا viewBox استفاده می کنیم:
<svg width="800" height="600" viewbox="-100 -100 400 300">
<!-- SVG content drawn onto the SVG canvas -->
</svg>
در مثال قبل دیدیم که اعداد مثبت طرح را به سمت بالا و چپ حرکت می دادند پس در اینجا بالعکس این اتفاق می افتد و طرح به سمت پایین و راست انتقال پیدا می کند:
برای درک بهتر این موضوع همیشه viewBox را شبیه به یک قاب ببینیم و زمانی که که مقادیر آن تغییر می کند آن قاب را درون viewport جابجا کنیم و تصویر نهایی که در ذهن ما بوجود می آید جواب قصه ما خواهد بود.
در مثال بالا زمانی که مبدا viewBox ما 100 واحد منفی در هر دو جهت تغییر مکان داشت قاب 400 واحد در 300 واحد را بر روی viewport در نظر می گیریم که قرار است 100 واحد منفی به هر دو سمت جابجا شود:
آنچه که بعد از تغییرات از دریچه قاب ما قابل دیدن است نتیجه نهایی خواهد بود.
در مثال آخر این قسمت به جای اینکه ابعاد viewBox را کوچک تر از viewport در نظر بگیریم آنها را بزرگ تر می کنیم اما توجه داشته باشیم که فعلا نسبت ابعادی را حفظ کنیم:
<svg width="800" height="600" viewbox="0 0 1200 900">
<!-- SVG content drawn onto the SVG canvas -->
</svg>
در این مثال viewBox را 1.5 برابر viewport در نظر می گیریم و نتیجه بصورت زیر خواهد بود:
حال هر واحد viewBox از نظر افقی (viewport-width / viewBox-width
) برابر هر واحد viewport است. و هر واحد viewBox بر روی محور عمودی (viewport-height / viewBox-height
) برابر هر واحد viewport است.
این یعنی در این نگاشت هر واحد viewBox ما 0.66 برابر هر واحد viewport می باشد.
تا الان تمام مثال های ما نسبت ابعادی را حفظ می کردند و تغییر نمی دادند اما چه اتفاقی خواهد افتاد اگر مثلا در مثال آخر عرض و ارتفاع viewBox را برابر با 1000 و 500 قرار دهیم؟
در اینجا:
- کل viewBox درون viewport جا شده است.
- نسبت ابعادی viewBox حفظ شده است و کشیده نشده تا فضای viewport را پر کند.
- viewBox از نظر افقی و عمودی در وسط viewport قرار گرفته است.
این رفتار پیشفرض است. چه چیزی این رفتارها را کنترل می کند؟ و چگونه می توانیم این رفتارها را تغییر دهیم؟
ویژگی preserveAspectRatio
از ویژگی preserveAspectRatio برای این استفاده می شود که نسبت ابعادی طرح گرافیکی را مجبور کند تا حفظ شود و طرح از نسبت صحیحش خارج نشود.
اگر سیستم مختصات کاربری را با نسبت ابعادی متفاوت نسبت به سیستم مختصات viewport تعیین کنیم و اگر مرورگر بخواهد تا viewBox را بکشد تا اندازه اش متناسب با viewport شود این امر باعث می شود تا طرح گرافیکی ما تناسب صحیح خود را از دست بدهد. کشیدن viewBox در مثال قبل نتیجه زیر را خواهد داشت:
ویژگی preserveAspectRatio این اجازه را به ما می دهد که تغییر اندازه سیستم مختصات کاربری را بدون از دست دادن نسبت ابعادی انجام دهیم و همچنین مکان viewBox را درون viewport به چیزی غیر از وسط آن تغییر دهیم.
سینتکس رسمی این ویژگی بصورت زیر است:
preserveAspectRatio = defer? <align> <meetOrSlice>?
این ویژگی برای تمام ویژگی هایی که viewport جدید می سازند کاربرد دارد.
مقدار defer
اختیاری است و فقط وقتی موثر خواهد بود که از ویژگی preserveAspectRatio
بر روی عناصر تصویر استفاده شود. و روی عناصر دیگر تاثیری نخواهد داشت. پس در اینجا در مورد این مقدار بحثی نمی کنیم.
پارامتر align
باعث می شود که تغییر اندازه viewBox با حفظ نسبت ابعادی باشد یا نه و اگر این نسبت حفظ شود این پارامتر تراز بندی و یا همان مکان viewBox در viewport را نیز مشخص می کند.
پس در مثال بالا وقتی که نسبت ابعادی viewBox برابر با نسبت ابعادی viewport نیست و می خواهیم با وجود این موضوع طرح گرافیکی نسبت صحیح خود را حفظ کند باید از این پارامتر با مقداری غیر از none
استفاده کنیم.
مقدار none
باعث می شود تا نسبت ابعادی حفظ نشود.
preserveAspectRatio = "none"
تمام مقادیر دیگر ویژگی preserveAspectRatio
باعث می شوند تا نسبت ابعادی زمانی که viewBox درون viewport متناسب می شود، حفظ شود.
پارامتر آخر این ویژگی meetOrSlice
است که البته اختیاری می باشد و مقدار پیشفرض آن برابر با meet
است.
این پارامتر مشخص می کند که کل viewBox درون viewport قابل مشاهده باشد یا نه.
مقادیر meet
و slice
برای این ویژگی خیلی شبیه به مقادیر contain
و cover
برای ویژگی background-size هستند.
slice
شبیه به cover
و meet
شبیه به contain
می باشد.
meet
این مقدار پیشفرض است و طرح گرافیکی را تا زمانی که دو شرط زیر برقرار باشد بزرگ می کند:
- نسبت ابعادی در طرح گرافیکی حفظ شود.
- کل viewBox از طریق viewport قابل مشاهده باشد.
کلمه meet
از اینجا می آید که باعث می شود کل طرح دیده شود.
slice
دقیقا مثل مقدار cover
در ویژگی background-size عمل می کند و باعث می شود طوری طرح گرافیکی کشیده شود تا viewBox تمام سطح viewport را بپوشاند نه بیشتر.
که در این روش اگر نسبت ابعادی viewBox و viewport یکی نباشند قسمتی از viewBox از مرزهای viewport خارج شده و قابل مشاهده نخواهد بود.
کلمه slice
از همان برشی که احتمالا طرح گرافیکی می خورد می آید.
پس پارامتر meetOrSlice
برای ویژگی preserveAspectRatio
مشخص می کند که viewBox بطور کامل داخل viewport باشد و حتما قابل مشاهده باشد یا اینکه کشیده شود تا سراسر viewport را بپوشاند هر چند که احتمال دارد قسمتی از آن بریده شده و قابل مشاهده نباشد.
در مثال ما اگر اندازه viewBox را برابر با 200×300 قرار داده و هر دو مقدار meet و slice را برای ویژگی preserveAspectRatio
امتحان کنیم خواهیم داشت:
align
پارامتر align
در ویژگی preserveAspectRatio
به غیر از none
نه (9) مقدار دیگر می پذیرد که همه آنها نسبت ابعادی طرح گرافیکی را حفظ می کنند و همچنین مکان viewBox را نسبت به viewport مشخص می کنند.
align
شبیه به ویژگی background-position با مقدار درصد عمل می کند. تنها فرقی که این دو دارند در این است که align
در SVG ترازبندی را بر اساس یک محور خاص viewBox و محور متناظر آن در viewport انجام می دهد.
برای درک بهتر مقادیر این پارامتر بهتر است اول با محورها آشنا شویم.
مقادیر <min-x>
و <min-y>
را یادتان هست؟ قرار است از آنها برای تعریف محور min-x و محور min-y روی viewBox استفاده کنیم.
بعلاوه دو محور max-x و max-y را تعریف می کنیم که که به ترتیب مکان های <width> + <min-x> و <height> + <min-y> را دارند.
و در آخر دو محور mid-x و mid-y را داریم که در وسط این دو محور دیگر در هر راستا قرار دارند. البته می توان مکان دقیق آنها را بترتیب به این صورت حساب کرد:
<min-x> + (<width>/2)
<min-y> + (<height>/2)
در تصویر زیر محورها مشخص شده اند که محورهای min-x و min-y در مکان پیشفرض خود یعنی همان صفر قرار دارند و داریم: viewBox = "0 0 300 300"
در تصویر بالا خط چین های خاکستری محورهای viewport هستند.
none
همانطور که قبلا گفته شد این مقدار باعث می شود تا طرح گرافیکی در زمان تغییر اندازه مجبور به حفظ نسبت ابعادی نباشد. وقتی از none
استفاده می کنیم پارامتر meetOrSlice
نادیده گرفته می شود.
xMinYMin
طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.
محور min-x در viewBox با کمترین مقدار محور X در viewport تراز می شود.
محور min-y در viewBox با کمترین مقدار محور Y در viewport تراز می شود.
شبیه به background-position: 0% 0%;
عمل می کند.
xMinYMid
طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.
محور min-x در viewBox با کمترین مقدار محور X در viewport تراز می شود.
نقطه وسط راستای Y در viewBox با نقطه وسط راستای Y در viewport تراز می شود.
شبیه به background-position: 0% 50%;
عمل می کند.
xMinYMax
طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.
محور min-x در viewBox با کمترین مقدار محور X در viewport تراز می شود.
محور max-y در viewBox با بزرگترین مقدار راستای Y در viewport تراز می شود.
شبیه به background-position: 0% 100%;
عمل می کند.
xMidYMin
طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.
نقطه وسط راستای X در viewBox با نقطه وسط راستای X در viewport تراز می شود.
محور min-y در viewBox با کمترین مقدار محور Y در viewport تراز می شود.
شبیه به background-position: 50% 0%;
عمل می کند.
xMidYMid
(مقدار پیشفرض)
طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.
نقطه وسط راستای X در viewBox با نقطه وسط راستای X در viewport تراز می شود.
نقطه وسط راستای Y در viewBox با نقطه وسط راستای Y در viewport تراز می شود.
شبیه به background-position: 50% 50%;
عمل می کند.
xMidYMax
طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.
نقطه وسط راستای X در viewBox با نقطه وسط راستای X در viewport تراز می شود.
محور max-y در viewBox با بزرگترین مقدار راستای Y در viewport تراز می شود.
شبیه به background-position: 50% 100%;
عمل می کند.
xMaxYMin
طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.
محور max-x در viewBox با بزرگترین مقدار راستای X در viewport تراز می شود.
محور min-y در viewBox با کمترین مقدار محور Y در viewport تراز می شود.
شبیه به background-position: 100% 0%;
عمل می کند.
xMaxYMid
طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.
محور max-x در viewBox با بزرگترین مقدار راستای X در viewport تراز می شود.
نقطه وسط راستای Y در viewBox با نقطه وسط راستای Y در viewport تراز می شود.
شبیه به background-position: 100% 50%;
عمل می کند.
xMaxYMax
طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.
محور max-x در viewBox با بزرگترین مقدار راستای X در viewport تراز می شود.
محور max-y در viewBox با بزرگترین مقدار راستای Y در viewport تراز می شود.
شبیه به background-position: 100% 100%;
عمل می کند.
در مثال پرنده قشنگ ما وقتی داریم viewBox="0 0 200 300"
بعضی مقادیر نتیجه یکسان خواهند داشت. در تصاویر زیر برای پارامتر meetOrSlice
مقدار پیشفرض یا همان meet
را در نظر می گیریم پس در نتیجه همیشه طرح ما قابل مشاهده خواهد بود:
حال اگر بجای meet
از slice
نتایج متفاوت خواهد بود. در تصاویر زیر مشاهده می کنید که چطور طرح کشیده می شود تا کل فضای viewport را بپوشاند. یعنی عرض 200 واحدی viewBox عرض 800 واحدی viewport را می پوشاند و چون قرار است نسبت ابعادی طرح حفظ شود قسمت هایی از آن قابل مشاهده نیست:
توجه داشته باشید که اگر مقادیر <min-x>
و <min-y>
تغییر کنند محورهای وسط و بیشینه نیز تغییر خواهند کرد.
به عنوان نمونه اگر در مثال قبلی viewBox را بصورت زیر تغییر دهیم:
viewBox = "100 0 200 300"
و مقادیر preserveAspectRatio
را همان مقادیر پیشفرض یعنی xMidYMid meet
قرار می دهیم:
تمرین کنیم
در لینکهای زیر ابزارهایی وجود دارند که می توانیم با تغییر تمام ویژگی ها و پارامترهایی که گفته شد به درک بهتر موضوع کمک کنیم.
بسیار کامل و مفید بود موفق باشید
سلام و خسته نباشید
چطوری میشه از فونت svg در سایت استفاده کرد ؟ مثل همین سایت شما که از svg استفاده کردین بجای فونت آسم
سلام.
https://css-tricks.com/svg-sprites-use-better-icon-fonts
با سلام اون قسمت مربوط به viewbox که گفتین مقدار مثبت مبدا رو به سمت راست و بالا حرکت میده در حالی که انگار برعکسه تو نمونه ای هم که دادین به این شکل هستش که ۱۰۰ پیکسل به سمت راست و ۱۰۰ پیکسل هم به سمت پایین حرکت میکنه
اعداد مثبت طرح را به سمت بالا و چپ حرکت می دادند پس در اینجا بالعکس این اتفاق می افتد و طرح به سمت پایین و راست انتقال پیدا می کند
درسته یا این که من اشتباه میکنم .
سلام، کجا گفته شده مبدا رو به سمت راست و بالا حرکت میدیم؟ میشه متن دقیقش رو اینجا کپی کنید؟
در مثال قبل دیدیم که اعداد مثبت طرح را به سمت بالا و چپ حرکت می دادند پس در اینجا بالعکس این اتفاق می افتد و طرح به سمت پایین و راست انتقال پیدا می کند
آقای سیدی یه سئوال داشتم معنی این جمله چیه .
.
نسبت ابعادی طرح گرافیکی را حفظ میکند .
از چه لحاظ حفظ میکند یعنی اندازه طول و عرض حفظ میشه؟؟