Необходимо сделать адаптивный SVG
.
Как сделать так, чтобы при изменении размеров изображения (или viewport
-а), дочерние элементы SVG
перемещались и перестраивались (как в адаптивной вёрстке сайтов).
Как сделать такой SVG
?
Можно создать "адаптивное" svg-изображение. Для этого нужно прописать внутри него css-медиазапросы и двигать элементы через transform
.
Пример изображения:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="200px" height="200px" preserveAspectRatio="none">
<style>
circle,
rect{
stroke-width:2px;
fill:none;
stroke:orange;
}
@media (max-width: 120px){
circle{
transform:translateX(50px);
}
rect{
transform:translate(-60px,80px);
}
}
</style>
<circle cx="40" cy="40" r="34" />
<rect x="100" y="10" width="80" height="60" />
</svg>
Далее вставляем его на страницу(использовал data:url т.к. SO не хочет принимать svg картинки и ссылки без https, но это тот же самый svg):
$('input').on('input',function(){
$('img').width(this.value);
})
*{
box-sizing:border-box;
vertical-align:top;
}
img{
max-width:100%;
border:1px solid;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMjAwIDIwMCIgd2lkdGg9IjIwMHB4IiBoZWlnaHQ9IjIwMHB4IiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJub25lIj4NCiAgPHN0eWxlPg0KICAgIGNpcmNsZSwNCiAgICByZWN0ew0KICAgICAgc3Ryb2tlLXdpZHRoOjJweDsNCiAgICAgIGZpbGw6bm9uZTsNCiAgICAgIHN0cm9rZTpvcmFuZ2U7DQogICAgfQ0KICAgIEBtZWRpYSAobWF4LXdpZHRoOiAxMjBweCl7DQogICAgICBjaXJjbGV7DQoJCXRyYW5zZm9ybTp0cmFuc2xhdGVYKDUwcHgpOw0KCSAgfQ0KCSAgcmVjdHsNCgkJdHJhbnNmb3JtOnRyYW5zbGF0ZSgtNjBweCw4MHB4KTsNCgkgIH0NCiAgICB9DQogIDwvc3R5bGU+DQogIDxjaXJjbGUgY3g9IjQwIiBjeT0iNDAiIHI9IjM0IiAvPg0KICA8cmVjdCB4PSIxMDAiIHk9IjEwIiB3aWR0aD0iODAiIGhlaWdodD0iNjAiIC8+DQo8L3N2Zz4=" />
<label for="controller">Тут задавать ширину для картинки</label>
<input id="controller" type="number" min="70" max="500" step="5" />
Набросал пример кода на чистом svg и разумеется здесь мы не увидим как меняется расположение svg объектов то привожу пример в: https://codepen.io/topicstarter/pen/oPBzvw?editors=1000 в котором изменение положения объектов произойдёт при разрешении меньше 600px.
что бы увидеть здесь адаптивность svg надо открыть пример кода на всю страницу а сжать сам браузер до менее 600px
img preview :
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<svg viewbox="0 250 200" id="svg">
<defs>
<style>
#svg{
width:210px;
height:100px;
}
#rect{
width:50px;
height:40px;
fill:red;
x:20px;
y:30px;
}
#circle{
cx:150px;
cy:50px;
fill:blue;
r:40px;
}
@media (max-width:600px){
#svg{
width:200px;
height:140px;
}
#rect{
width:50px;
height:40px;
fill:red;
x:70px;
y:5px;
fill:blue;
}
#circle{
cx:95px;
cy:90px;
fill:blue;
r:40px;
fill:red;
}
}
</style>
</defs>
<rect id="rect"></rect>
<circle id="circle"></circle>
</svg>
Вариант на JS
(подобно flex-wrap
в CSS
):
const $d = document;
let rects = $d.getElementsByTagName('rect');
const arrangement = e => {
let windowWidth = $d.documentElement.clientWidth;
let offset_x = 20;
let offset_y = 20;
let next_offset_y = offset_y;
let offset = 20;
let maxH = 0;
let maxW = 0;
for (let i = 0, len = e.length; i < len; i++) {
let w = parseInt(getComputedStyle(e[i]).width);
let h = parseInt(getComputedStyle(e[i]).height);
if (h > maxH) {
maxH = h;
}
if (w > maxW) {
maxW = w;
}
if (maxW + w + offset_x + offset + offset + offset > windowWidth) {
set(e, i, offset_x, offset_y);
offset_y += offset + next_offset_y;
offset_x = 20;
maxH = h;
} else {
set(e, i, offset_x, offset_y);
offset_x += w + offset;
next_offset_y = maxH;
}
}
};
const set = (e, i, offset_x, offset_y) => {
e[i].setAttribute('x', offset_x);
e[i].setAttribute('y', offset_y);
}
arrangement(rects);
window.onresize = function(e) {
arrangement(rects);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
overflow: hidden;
}
html {
font-size: 62.5%;
}
html,
body {
height: 100%;
}
.wrapper {
width: 100%;
height: 100%;
}
.wrapper svg {
width: inherit;
height: inherit;
background-color: hsl(10, 0%, 70%);
}
.wrapper svg .main-area rect {
width: 25px;
height: 25px;
stroke: #000;
stroke-width: 0.125rem;
}
.wrapper svg .main-area rect.rect1 {
width: 70px;
height: 25px;
}
.wrapper svg .main-area rect.rect2 {
width: 25px;
height: 70px;
}
.wrapper svg .main-area rect.rect3 {
width: 70px;
height: 50px;
}
<div class="wrapper">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/2000/svg" version="1.1">
<g class="main-area" fill="hsl(50,100%,70%)">
<rect/>
<rect/>
<rect/>
<rect/>
<rect class='rect3'/>
<rect class='rect3'/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect class='rect1'/>
<rect/>
<rect class='rect2'/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect class='rect2'/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
<rect/>
</g>
</svg>
</div>
Это можно сделать, используя любую js библиотеку для работы с SVG.
К примеру я взял SVG.js:
Сразу предоставлю рабочий пример, а ниже код примера:
var draw = SVG('banner');
var bg = draw
.rect('100%', '100%')
.attr({ fill: '#ffeb3b' });
var elem1 = draw
.ellipse(100, 100)
.attr({ fill: '#f06' });
var elem2 = draw
.rect(150, 100)
.attr({ fill: '#f06' });
bunnerUpdate();
window.onresize = bunnerUpdate;
function bunnerUpdate() {
if (window.innerWidth > 400) {
draw.size(400, 200);
elem1.move(50, 50);
elem2.move(200, 50);
}
else {
draw.size('100%', 350);
elem1.move(window.innerWidth / 2 - 50, 50);
elem2.move(window.innerWidth / 2 - 75, 200);
}
}
body {
margin: 0;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.5/svg.min.js"></script>
<div id="banner"></div>
Виртуальный выделенный сервер (VDS) становится отличным выбором
В следующем коде я ожидаю, что при нажатии на кнопку отобразится текст из трех строкОднако, после нажатия появляется одна строка Some text<br>Some...