Я сделал «кнопку гамбургера» в SVG, как показано ниже.
body {
margin: 0;
text-align: center;
}
svg#ham-btn {
margin: 2rem;
border: 1px solid black;
fill: #383838;
}<svg id = "ham-btn" width = "107.5px" height = "80px" viewBox = "0 0 80 80" preserveAspectRatio = "xMidYMid meet" xmlns = "http://www.w3.org/2000/svg">
<style>
#ham-btn {
cursor: pointer;
}
#ham-btn:hover #r1 {
outline: 1px solid transparent;
transition: transform 0.2s;
transform-origin: 50% 50%;
transform: rotate(37deg) translate(0%, 28.75%) scaleX(1.1);
}
#ham-btn:hover #r2 {
transition: transform 0.2s;
transform: translate(120%, 0);
}
#ham-btn:hover #r3 {
outline: 1px solid transparent;
transition: transform 0.2s;
transform-origin: 50% 50%;
transform: rotate(-37deg) translate(0%, -28.75%) scaleX(1.1);
}
</style>
<rect id = "r3" x = "0" y = "71.25%" width = "100%" height = "15%" rx = "5%" />
<rect id = "r2" x = "0" y = "42.5%" width = "100%" height = "15%" rx = "5%"/>
<rect id = "r1" x = "0" y = "13.75%" width = "100%" height = "15%" rx = "5%" />
</svg>Вопрос
Прямо сейчас, если я хочу сделать кнопку меньше, мне нужно вручную уменьшить размеры области просмотра и viewBox на такое же количество пикселей.
Есть ли способ сделать это более отзывчивым? Например, сделав viewBox процентом от области просмотра?
Согласно спецификации, кажется, что viewBox должен быть <number> и, следовательно, не может быть процентным.
Есть предположения?
Спасибо.
Примечание 1
Я не добавил к кнопке никаких специальных возможностей или других функций. Этот вопрос касается его отзывчивости.
Заметка 2
Я знаю, что могу сделать область просмотра SVG процентом от ее контейнера / области просмотра браузера.
К сожалению, это не решает мою проблему, поскольку для того, чтобы эта кнопка работала, мое соотношение viewBox-to-viewport должно оставаться неизменным (в противном случае кнопка теряет свою форму).
Таким образом, я хотел, чтобы viewBox находился в процентах от области просмотра.
В случае, если это интересно, в моем решении используются следующие преимущества:
viewBox шире окна просмотра, но имеет такую же высотуpreserveAspectRatio используется для горизонтального центрирования rect.rect указаны в процентах от viewBox.outline предназначен для исправления проблемы Firefox с неровными линиями после преобразования.
Редактировать:
Если это будет полезно для будущих посетителей, последнюю кнопку, включая полную доступность, можно найти здесь: https://codepen.io/magnusriga/pen/KrrJKa
не заинтересованы в чистом решении CSS? как этот: stackoverflow.com/questions/53555133/… или этот: stackoverflow.com/questions/53270861/…
Привет @TemaniAfif. Спасибо за ссылки. Я также ранее реализовал меню в HTML + CSS, но недавно погрузился в SVG (как вы знаете) и нашел его невероятно эффективным для графики и анимации. На мой взгляд, для гамбургер-меню SVG кажется более простым и менее хакерским подходом по сравнению с HTML + CSS с абсолютными элементами.
Теперь мне просто нужно понять, почему установка ширины / высоты SVG в CSS - это не то же самое, что указание этого в самих атрибутах представления svg (как я думал, это сказано в спецификации).
@enxaneta Начальное значение атрибутов представления ширины / высоты в элементе SVG составляет 100% (родительского контейнера), если я правильно понимаю. Удаление высоты нарушит разницу в соотношении ширины / высоты между окном просмотра SVG и окном просмотра, от которого зависит центрирование окна просмотра (он использует preserveAspectRatio).






Добавьте свойства ширины и высоты в свой svg css. С установленной шириной и автоматической высотой.
body {
margin: 0;
text-align: center;
}
svg#ham-btn {
margin: 2rem;
border: 1px solid black;
fill: #383838;
/* percentage of viewport - height will autocalculate */
width: 7vw;
height: auto;
}<svg id = "ham-btn" width = "107.5px" height = "80px" viewBox = "0 0 80 80" preserveAspectRatio = "xMidYMid meet" xmlns = "http://www.w3.org/2000/svg">
<style>
#ham-btn {
cursor: pointer;
}
#ham-btn:hover #r1 {
transition: transform 0.2s;
transform-origin: 50% 50%;
transform: rotate(37deg) translate(0%, 28.75%) scaleX(1.1);
}
#ham-btn:hover #r2 {
transition: x 0.2s;
x: 120%;
}
#ham-btn:hover #r3 {
transition: transform 0.2s;
transform-origin: 50% 50%;
transform: rotate(-37deg) translate(0%, -28.75%) scaleX(1.1);
}
</style>
<rect id = "r3" x = "0" y = "71.25%" width = "100%" height = "15%" rx = "5%" />
<rect id = "r2" x = "0" y = "42.5%" width = "100%" height = "15%" rx = "5%"/>
<rect id = "r1" x = "0" y = "13.75%" width = "100%" height = "15%" rx = "5%" />
</svg>Привет. Я знаю, что могу сделать окно просмотра svg процентным от его контейнера. Я думал о viewBox.
@Magnus какая-либо конкретная причина изменения атрибута viewBox в HTML / SVG? Afaik, нет возможности изменить это через CSS, но JS может помочь, хотя и не обязательно. Добиться желаемого эффекта (если я правильно понял) можно, задав ширину / высоту.
Если вы измените ширину / высоту области просмотра без изменения viewBox, кнопка потеряет свою форму. Я просто добавил несколько примечаний к OP, в которых объясняется, как работает мое решение.
PS: Черный ящик вокруг гамбургера (область просмотра) должен находиться на точно таком же расстоянии% от прямоугольников при любом размере контейнера. Итак, если вы сделаете его тоньше, как вы это делали, весь svg потеряет свою форму. Черный ящик (окно просмотра) и гамбургер принадлежат друг другу. При наведении курсора крестик аккуратно указывает на углы этого черного ящика (область просмотра).
@Magnus Я обновил ответ - добавил height: auto Это должно сохранить соотношение сторон.
Я думал, что установка ширины / высоты svg в CSS перезапишет собственную ширину / высоту окна просмотра SVG (107,5 пикселей и 80 пикселей). Разве это не так?
Кроме того, есть идеи, почему края выглядят неровными после преобразования в течение примерно 0,5 секунды в Firefox? То же самое не происходит в хроме.
@ Магнус, да. Свойства CSS "перезаписывают" атрибуты HTML по умолчанию.
Я не думаю, что он перезаписывает размеры области просмотра svg 107,5 пикселей и 80 пикселей? Если вы попытаетесь изменить их вручную, не меняя viewBox, вы увидите, что форма теряет свою форму.
Я исправил проблемы с Firefox.
Думаю, я понимаю, почему ваше решение работает. Это связано с тем, что явно заданные ширина и высота области просмотра используются только для определения внутреннего соотношения сторон, отличного от того, что установил бы viewBox (если ширина / высота не были явно указаны). Фактическая ширина и высота области просмотра затем перезаписываются CSS, но внутреннее соотношение сторон svg сохраняется (107,5 / 80). Это соотношение сторон затем используется при указании height: auto в CSS. Если бы мы не указали auto в CSS, высота упала бы до 80 пикселей, как установлено svg. Если это так, не могли бы вы добавить это объяснение к своему ответу?
Как я уже сказал в своем комментарии: я бы удалил ширину и высоту элемента svg. Затем в CSS я бы сделал ширину SVG: 20%. Я делаю ширину SVG 50% ширины окна.
Чтобы сохранить пропорции, я положил «гамбургер» внутрь <symbol viewBox = "0 0 80 80">. Грубо говоря, в этом случае preserveAspectRatio = "xMidYMid meet" вам больше не нужен.
body {
margin: 0;
text-align: center;
}
svg#ham-btn {
width: 20%;
margin:auto;
top:0;bottom:0;left:0;right:0;
border: 1px solid black;
fill: #383838;
position:absolute;
}<svg id = "ham-btn" viewBox = "0 0 107.5 80" preserveAspectRatio = "xMidYMid meet" xmlns = "http://www.w3.org/2000/svg">
<style>
#ham-btn {
cursor: pointer;
}
#ham-btn:hover #r1 {
outline: 1px solid transparent;
transition: transform 0.2s;
transform-origin: 50% 50%;
transform: rotate(37deg) translate(0%, 28.75%) scaleX(1.1);
}
#ham-btn:hover #r2 {
transition: transform 0.2s;
transform: translate(120%, 0);
}
#ham-btn:hover #r3 {
outline: 1px solid transparent;
transition: transform 0.2s;
transform-origin: 50% 50%;
transform: rotate(-37deg) translate(0%, -28.75%) scaleX(1.1);
}
</style>
<symbol id = "s" viewBox = "0 0 80 80">
<rect id = "r3" x = "0" y = "71.25%" width = "100%" height = "15%" rx = "5%" />
<rect id = "r2" x = "0" y = "42.5%" width = "100%" height = "15%" rx = "5%"/>
<rect id = "r1" x = "0" y = "13.75%" width = "100%" height = "15%" rx = "5%" />
</symbol>
<use xlink:href = "#s" width = "80" x = "13.75"/>
</svg>Интересное решение, создание другого окна просмотра во внешнем окне просмотра. Я предполагаю, что другим вариантом было бы использовать вложенный svg вместо символа, поскольку они оба устанавливают новое окно просмотра. В любом случае, не могли бы вы добавить объяснение того, как все измерения связаны вместе, то есть каковы каждое начальное и вычисленное значения. Я предполагаю, что ширина / высота внутреннего окна просмотра составляет 100% (начальное) от размеров внешней ширины, что, в свою очередь, составляет 100% от родительского контейнера. Однако мы устанавливаем ширину в CSS, поэтому внешний svg получает ширину области просмотра 20%, а затем использует внутреннее измерение SVG для заполнения высоты. 1/2
2/3 .... Внутренние размеры (согласно спецификации: w3.org/TR/SVG2/coords.html#SizingSVGInCSS) равны viewBox.width / viewBox.height (поскольку мы не указали и ширину области просмотра, и высоту области просмотра как абсолютные значения). Наконец, это означает, что внутренний и внешний видовой экран равны по высоте / ширине, и оба имеют внутреннее соотношение сторон 107,5 / 80, которое используется CSS для вычисления высоты (начальное значение которого, если не указано, равно auto).
3/3 ... Все это означает, что нам фактически не нужно созданное вами внутреннее окно просмотра. У нас может быть только одно окно просмотра (как в OP), сохранить ширину и высоту области просмотра, чтобы сделать внутренние размеры 107/80, затем изменить ширину в CSS по желанию и установить высоту на auto (чтобы она не уменьшалась до 80 пикселей. ). В этом решении явно заданные ширина и высота области просмотра используются только для установки внутреннего измерения, отличного от того, что указывает viewBox. Фактическая ширина и высота области просмотра перезаписываются CSS.
Я бы удалил ширину и высоту элемента svg. Тогда в CSS я бы сделал SVG
width:50%. Вам не нужно декларировать высоту, если вам не нужно сжать / растянуть изображение.