When tapping this SVG element on an iOS device in Safari (iOS Chrome is fine, I'm currently unable to check desktop Safari) it does not play the transition animation to fade in the replacement <g id="training-sub-menu">
. I know the animation works because there's some odd behaviour where if I long press where one of the links should be, it opens some iOS context menu and then fades in the <g>
(I put a 2s transition to show this). So I think I'm just getting stuck on how to trigger the animation where all other browsers seem to respond to :hover
.
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 306.12 409.2">
<defs>
<style type="text/css">
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600');
.font-md {
font-family: 'Poppins';
font-size: 10px;
font-weight: 500;
}
:root {
--yellow: #f6b034;
}
.training {
fill: var(--yellow);
}
.sub-menu {
opacity: 0;
visibility: hidden;
height: 0;
}
.sub-menu > g {
opacity: 0;
-webkit-transition: opacity 2s ease-in-out;
}
.has-dropdown:hover + .sub-menu,
.has-dropdown:hover + .sub-menu > g {
opacity: 1;
visibility: visible;
height: auto;
pointer-events: visiblePainted;
transform: unset;
}
.has-dropdown:hover {
opacity: 0;
visibility: hidden;
height: 0;
}
.sub-menu:hover {
opacity: 1;
visibility: visible;
height: auto;
pointer-events: none;
}
.sub-menu:hover > g {
opacity: 1;
}
</style>
</defs>
<g id="training" class="has-dropdown">
<path class="training" d="m0,256c0-27.61,22.39-50,50-50,27.61,0,50,22.38,50,49.99,0-.21.02-.42.02-.63v29.39c0,11.06,8.45,20.15,19.25,21.15.02,0,.04.09,0,.09-.04,0-62.38,0-69.27,0,0,0,0,0,0,0s0,0,0,0h-.62c.1,0,.21,0,.31,0C22.22,305.82,0,283.51,0,256Z"/>
<text class="font-md" transform="translate(31 285)">Training</text>
</g>
<g id="training-sub-menu" class="sub-menu">
<path class="training" d="m0,256c0-27.61,22.39-50,50-50,27.61,0,50,22.38,50,49.99,0-.21.02-.42.02-.63v29.39c0,11.06,8.45,20.15,19.25,21.15.02,0,.04.09,0,.09-.04,0-62.38,0-69.27,0,0,0,0,0,0,0s0,0,0,0h-.62c.1,0,.21,0,.31,0C22.22,305.82,0,283.51,0,256Z"/>
<g id="text">
<text class="font-md sub-menu-item" transform="translate(31 285)">
<a href="https://google.com" target="_parent">Google</a>
</text>
<text class="font-md sub-menu-item" transform="translate(31 265)">
<a href="https://google.com" target="_parent">Google</a>
</text>
<text class="font-md sub-menu-item" transform="translate(31 245)">
<a href="https://google.com" target="_parent">Google</a>
</text>
</g>
</g>
</svg>
I attempted to wrap the <text>
elements in a <g>
and apply the transition on the <g>
as per this answer: CSS transform on SVG text element not working in Safari but no luck.
I also tried using -webkit-transition
.
Lastly I tried using onclick
for the divs on the page that loads in this SVG as per CSS :hover not working on iOS Safari and Chrome but that didn't work either.
Is it potentially due to not having a clickable element (as per the footnote on this page: https://caniuse.com/mdn-css_selectors_hover)?
Ended up just going the JavaScript route which is a shame because I think getting the CSS solution to work would have been a bit more elegant. I've ended up with a set of rudimentary JavaScript functions that are in the parent HTML, and use click event handlers which manipulate the SVG to toggle classes:
<script>
function showSubMenu(e) {
e.currentTarget.classList.toggle('hidden');
e.currentTarget.nextElementSibling.classList.toggle('visible');
}
function closeAllMenus(e) {
if (!e.target.parentElement.classList.contains('has-dropdown')) {
var subMenus = svgDoc.querySelectorAll('.sub-menu');
subMenus.forEach(subMenu => {
subMenu.classList.add('hidden');
subMenu.classList.remove('visible');
})
var dropdowns = svgDoc.querySelectorAll('.has-dropdown');
dropdowns.forEach(dropdown => {
dropdown.classList.remove('hidden');
dropdown.classList.add('visible');
})
}
}
document.addEventListener('click', closeAllMenus);
var svgObj;
if (screen.width > 767) {
svgObj = document.getElementById("svg-object-desktop");
}
else {
svgObj = document.getElementById("svg-object-mobile");
}
var svgDoc;
svgObj.addEventListener('load', function() {
svgDoc = svgObj.contentDocument;
var dropdowns = svgDoc.querySelectorAll('.has-dropdown');
dropdowns.forEach(dropdown => {
dropdown.addEventListener('click', showSubMenu)
});
});
</script>
I use two different SVGs for mobile and non-mobile hence the check.
On the plus side the corresponding CSS is a bit simpler now:
.sub-menu > g {
transition: opacity 0.5s ease-in-out;
}
.hidden,
.sub-menu {
opacity: 0;
visibility: hidden;
height: 0;
transition: opacity 0.5s ease-in-out;
}
.visible,
.has-dropdown {
opacity: 1;
visibility: visible;
height: auto;
pointer-events: visiblePainted;
transform: unset;
}
Works fine in iOS Safari now.