Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessibility #47

Open
sgilbert-gouv opened this issue Nov 18, 2020 · 2 comments
Open

Accessibility #47

sgilbert-gouv opened this issue Nov 18, 2020 · 2 comments
Labels
accessibility Related to accessibility enhancement New feature or request

Comments

@sgilbert-gouv
Copy link

sgilbert-gouv commented Nov 18, 2020

Hey there, great plugin btw!

It would be amazing if it could transfer the img alt attribute to the a title attribute on svg tag. That way, we can ensure accessibility, according to W3C.

I know I could just add a title attribute on the .svg file itself, but what if I have multiple languages? So yeah, it needs to transfer from the img to svg as well!

I might try to do a pull request if I have the time.

Thanks!

@waruyama
Copy link
Collaborator

waruyama commented Dec 4, 2020

@sgilbert-gouv

If I understand you correctly you suggest to simply copy the alt attribute to the <svg> element? This would be really easy to implement.

But on stackoverflow there was a complaint that <svg> does not support the alt attribute, so I came up with another idea.

  1. When image is loaded, load the SVG and replace the img with the svg (just like we do it now)
  2. Set the computed style for all SVG elements as inline style
  3. Create a new <img> element from the SVG and replace the SVG.

Here is a fiddle that shows how to replaces the SVG with an img. This does not use SVGInject, but shows how a styled <img> element can be created. It even works on Internet Explorer.

We could take this even further and just limit the style to some attributes like color and css variables on the SVG element. This way, the original <img> element can be directly converted to a styled SVG <img> element. Sounds pretty cool and IMO worth further looking into.

And just for the record, here is the sript for the fiddle above:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Styled img test</title>
</head>
<body style="color:red">

    <svg id="svg" width="100" height="100"><circle cx="50" cy="50" r="40" stroke="currentColor" stroke-width="4" fill="green"></circle></svg>

    <script>

        // Copy current style into svg element's style.
        // Taken from https://stackoverflow.com/a/44769098/3805458
        function copyStylesInline(destinationNode, sourceNode) {
            var containerElements = ["svg","g"];
            for (var cd = 0; cd < destinationNode.childNodes.length; cd++) {
                var child = destinationNode.childNodes[cd];
                if (containerElements.indexOf(child.tagName) != -1) {
                    copyStylesInline(child, sourceNode.childNodes[cd]);
                    continue;
                }
                var style = sourceNode.childNodes[cd].currentStyle || window.getComputedStyle(sourceNode.childNodes[cd]);
                if (style == "undefined" || style == null) continue;
                for (var st = 0; st < style.length; st++){
                    child.style.setProperty(style[st], style.getPropertyValue(style[st]));
                }
            }
        }

        let svgEl = document.getElementById("svg");

        // Make style for SVG and all child elements inline
        svgEl.xmlns="http://www.w3.org/000/svg";
        copyStylesInline(svgEl, svgEl);

        // create data url
        let svgStr = new XMLSerializer().serializeToString(svgEl);
        let blob = new Blob([svgStr], {type:'image/svg+xml;charset=utf-8'});
        let svgUrl = URL.createObjectURL(blob);
        let imgEl = document.createElement('img');
        imgEl.src = svgUrl;

        // When loaded, replace <svg> with <img> element
        imgEl.onload = function() {
            URL.revokeObjectURL(svgUrl);
            svgEl.parentNode.replaceChild(imgEl, svgEl);
        };

    </script>
</body>
</html>


@waruyama
Copy link
Collaborator

waruyama commented Dec 4, 2020

To follow up on my idea above, here is another approach that never actually injects the SVG. This would copy some style attributes from the <img> element to the <svg> element and the create a data URL that will the set as the image's new src attribute. So as a result, the image will still be in the DOM, but the SVG has been styles. The issues I see are:

  • Styling occurs only once. If the css or style later changes, the change will not be reflected in the SVG. This should not be an issue for most use cases.
  • Before applying the style it must be ensured that all style sheets are loaded, otherwise the images are displayed with a wrong style. I do not know if there can be problems, but this should be investigated.
  • If we want to allow css variables (custom properties), these must be defined somewhere in advance. Even copying all styles from the image to the SVG will not copy the SVG variables. This is a bit of a shame, but we should try to find an easy to use workaround.

Here is the jsfiddle with the proof of concept (using a hard coded SVG string). The SVG is never injected, but the image gets styled.

And here is the whole thing as one single file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Styled img test</title>
    <style>
        .purple-yellow {
          color: teal;
          --color2: goldenrod;
        }
    </style>
</head>
<body>

    <img id="img1" class="purple-yellow"/>

    <script>

        let domParser =  new DOMParser();

        // This is the biggest issue. We have to know the properties in advance if we want to
        // use custom properties, because they are not listed by getComputedStyle().
        let styleProps = ['color', '--color2'];


        // Create svg element.
        let svgStr = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="40" stroke="var(--color2)" stroke-width="4" fill="currentColor" /></svg>';
        let svgEl =  domParser.parseFromString(svgStr, 'text/xml').documentElement;


        // Copy style from image element to svg element
        let imgEl = document.getElementById('img1');
        if (styleProps != null && styleProps.length > 0) {
          let imgStyle = window.getComputedStyle(imgEl);
          for (let i = 0; i < styleProps.length; i++) {
            svgEl.style.setProperty(styleProps[i], imgStyle.getPropertyValue(styleProps[i]));
          }
        }

        // Create data URL from svg and set is as src attribute
        let svgStr2 = new XMLSerializer().serializeToString(svgEl);
        let blob = new Blob([svgStr2], {type:'image/svg+xml;charset=utf-8'});
        let svgUrl = URL.createObjectURL(blob);
        imgEl.src = svgUrl;
        imgEl.onload = function() {
          // Cleanup. We could also reuse the url if the same style with the same original
          // src attribute is used again.
          URL.revokeObjectURL(svgUrl);
        };

    </script>
</body>
</html>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accessibility Related to accessibility enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants