Having only one of two images 'exist' (via SVG detection)

Hi. Could someone check out this code sample I did, and let me know if there’s some flaw in it?

I basically have two images, but based on whether the browser supports SVG, I have only ONE of the images ‘exist’… meaning the other one is not only invisible, but doesn’t take up any physical space.

I’m doing this because I have a page with an SVG animation, but since some systems may not support it, I want to have a still image as a fallback… but don’t want the ‘non-used’ image/animation to take up space (…otherwise, I end up with a large gap where the removed element would be).

So, my logic (correct or not) was to set the still image as the one used by default (making the SVG display:none, so it doesn’t take up any space on the page)… and then if the browser does support SVG, I swap the display status of the two elements (still image becomes display:none, and the SVG image becomes the used item instead).

So far, I have it working, except that the still image never goes away. The ‘no SVG support’ state works fine (the SVG is gone, and doesn’t take up space, and the still image is displayed)… but the ‘SVG support’ state works, but the still image remains, even though (as best as I can tell) I am properly setting it to be display:none.

Could someone have a look at the codepen sample (…it’s just a simplified version, for ease of reading…), and point out what errors I may be making here?

UPDATE: I have another question, which might be the answer to why this is not quite working… If I set an item as display:none, but then a little further down the page, I redefine it as display:inline, will it switch to inline, or is an item that has been set to display:none become non-stylable? That would explain what I’m seeing here…

i turn off/on items for display all the time… my entire website relies on it (rather than javascript).

items turn on and off as you would expect them using position: relative or similar.

using absolute and not seeing it on the scree usually means you have positioned outside the bounds of the viewport and since it’s absolute, it no longer flows in with the rest of the document.

@ladlon
First, you need to enclose your JavaScript in <script> tags.
Second, you can’t set styles that way in JS. You Could add a class name to the document and then modify your style rules. So if you add a class of svg to your body and then have a rules like:
.image1 {display: inline;} .svg .image1 {display: none;}

@droidgoo: I’m not understanding what you are saying. What does the position attribute have to do with this? I’m strictly using display:none or display:inline to swap whether it’s the SVG or the fallback image that ‘exists’. I use display, rather than just opacity/visibility, so that the ‘hidden’ item doesn’t push any of the other content/affect the flow. I always only want ONE of the two items. I’m not using absolute positioning at all (…I avoid position attributes generally anyway, as they seem to cause me great grief in responsive pages).

@RobM: Ya, that’s what I thought right away, too (since I figured you can’t just drop script into the HTML)… but when I actually did, it produced loads of errors, for some reason (virtually every semi-colon, etc got marked as an error). Oddly enough, it seemed to work without putting it in script tags (even though I know that can’t be right). I tried a number of different methods to change the CSS/style… including using things like get GetElementByID (which didn’t seem to work, giving me an undefined error, even though I tagged the images with IDs)… GetElementsByClassName (which half-worked, but started giving me undefined errors if/when I used .style.display = “none”, rather than .display = “none”, which seemed to work ‘better’ (again, despite it being wrong).

At this point, everything is actually working, except that the still image (fallback for the SVG) is either not going away in the ‘SVG supported’ state, or it is not showing up in the ‘SVG not supported’ state… It’s always one works, but the other doesn’t, whatever the combo. It’s almost like I can only define the display state once (with the still image, at least), and if I try a second time, it gets ignored. The SVG element is actualy showing/hiding fine. At this point, it’s just the fallback image that is currently giving me grief.

My current code logic is:

-Set both SVG and fallback image to display:none by defining a class for each (…so that if NOTHING is supported/works, none of the items are displayed, and the flow of the rest of the content isn’t disturbed… I don’t mind the graphics not showing on old/unfriendly devices, as long as everything else doesn’t get afffected). I define the two classes (and set the display to none) in the external CSS as well, as a fallback in case javascript is disabled (so, again, no graphics appear, rather than both showing up and conflicting with each other, if javascript is disabled, and the detection isn’t run).

-Detect SVG (as Boolean) and store in a variable.

-If variable is true, set the display of the SVG as inline.

-If variable is false, set the display of the fallback image as inline.

-In the body, have a div that has the SVG items, and in the same div, has the fallback image, with the assumption that only ONE of those will ‘exist’ (via the display attribute), and so the other will not only be invisible, but not take up any space. (I actually even took the precaution of also setting the height and width of the image to zero if SVG isn’t supported… just as an added precaution to ensure that even if it DID exist somehow, it would at least not push the other content/affect the flow).

Again, it all works, except for the fallback image not going away (or, with a variation of the code, not ever showing up).

I’m puzzled by the errors I’m getting when I try and do it verbetim/the way they are shown in examples… undefined errors.

I’ll post the current coding I’m using a little later today (…my work machine hasn’t been booted up yet, as I just got up recently… Long night!)

if ur not using position: absolute then display should behave as expected, winking thing in or out of the flow at your discretion… sorry if that wasn’t clear…

Well, ya, but that’s the thing… it’s not fully working. It SHOULD work, but it’s only 80% successful. Not sure why. That’s why I’m here…

Here’s the coding of in the HEAD:

<style>
.anim{
    display:none;
}
.fallback{
    display:none;
}
</style>

    <script>
    var svgSupport = !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect;


    if ( svgSupport ) {
        document.getElementById(".anim").style.display = "inline";
        console.log("Anim visible");

    }else if (svgSupport == false){
        document.getElementById(".fallback").style.display = "inline";
        console.log("Fallback visible");
    }
    </script>

…and then in the DIV, I have the SVG element and the fallback image, both with their approrpriate class attached to it.

I was never quite sure about the proper coding of the conditionals (ex. if ‘false’ should be in quotes or not… plus the specificity of the ‘else if’ is kind of redundant, since the value is binary, so if the first ‘if’ is false, it has to be true (…but, I put it in just as a safety).

What is wrong with my code logic?

Hi Ladlon,

I haven’t tested this but I would start with something like this

<head>
    <style>
        .hide {
            display: none;
        }
    </style>
</head>

<body>
    <!--****************-->
    <!-- Images go here -->
    <!--****************-->


    <script>

(function(){
        const svgSupport = !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect;
        let anim = document.querySelectorAll(".anim");
        let fallback = document.querySelectorAll(".fallback");

        if (svgSupport) {
            fallback.classList.add('hide');
            console.log("Anim visible");

        } else {
            anim.classList.add('hide');
            console.log("Fallback visible");
        }
})();

    </script>
</body>

Actually thinking about it you will probably have to loop through them

<head>
    <style>
        .hide {
            display: none;
        }
    </style>
</head>

<body>
<!--****************-->
<!-- Images go here -->
<!--****************-->


<script>

    (function(){
        const svgSupport = !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect;
        let anim = document.querySelectorAll(".anim");
        let fallback = document.querySelectorAll(".fallback");

        if (svgSupport) {
            for (let i = 0; i < fallback.length; i++) {
                fallback[i].classList.add('hide');
            }
            console.log("Anim visible");

        } else {
            for (let i = 0; i < anim.length; i++) {
                anim[i].classList.add('hide');
            }
            console.log("Fallback visible");
        }
    })();

</script>
</body>

@SureWeb: Thanks for the code. Much appreciated. I’ll try that out today.

I’m not sure what you mean by loop though them, as I only have two elements… the SVG canvas (animation), and a fallback image of that scene for devices that don’t support the animation (SVG, javascript, or whatever).

Normally, I’d want the fallback image to appear if there’s no support… but, worst case scenario, I’m also fine with neither showing up, but also not taking up the space they would normally take up (creating a big gap in the page).

It seems we are doing similar things, but you are using querySelector.

Again, it’s so weird that my current attempt is mostly working, but fails in one of the things that it otherwise succeeds on with the other element. It really feels like the style can only be defined once, and further attempts are ignored (even though that is certainly not the case). Really driving me nuts, trying to figure out what the issue is. Feels like it’s just some missing letter or something simple as that… yet everything appears to check out.

Okay, I’ll try your code and see if that changes things. I’m not sure if your methods are more ‘compatible’ than mine, as far as reliability/support, as I’m not familiar with it or how it is handled by browsers.

Hi Ladlon,

I wasn’t sure if you’d have multiple svg’s with fallbacks on the page. So in that case you would use the first one and change querySelectorAll to querySelector

You used getElementById but you were using classes, so I wouldn’t have thought it would work at all.

Hello again. Ya, nothing’s working.

In my current attempts, I’m getting either an undefined error or a null error. Not sure why.

It seems my most recent attempts (using the original code I posted) works, except that it’s unable to properly change the property.

Regarding your code, I’m confused, as you have a function being defined, but it’s not being called… or is it? This is partially new territory for me, so my comfort/familiarity level is not where I’d like it.

Task I’m after:
-If SVG (and java, etc and required things) are supported, display the SVG block (animation)
-If not, display the still image
-If even javascript is failing/not supported, don’t have either
-Do this in the most compatible, simple method, with a clean fail state (no gaps on page)

So, I figured have both items off by default, via CSS (maximum compatibility)… So, at worst, no graphics, and no gaps.
Then, if javascript supported, check for SVG compatibility.
If no SVG, but javascript is supported, then it can at least make the still image exist… so it’s at least nicer than no graphics.
If everything supported, then have the animation instead (and the still image doesn’t exist, and therefore doesn’t push the animation element via page flow).

The SVG support code seems to work.
The Javascript support check is done by simply setting both items to display:none via CSS… so if it works, the various coding is run… if not, the current state of things (both items ‘hidden’) is already there, without need of alteration via Javascript.

That’s my thinking… Not sure if the way I’m going about it is sound or not. When it comes to things like query and getElement I’m in somewhat unfamiliar territory.

BTW, ya, I had both a class and an ID assigned to the two elements, as I was jumping around between using getElement via ByClassName and ByID… I’ll take whichever one eventually works for me, as I assume they are equally valid/ideal.

I’m still getting those recent ‘null’ or ‘undefined’ errors lately… Not sure why those are suddenly popping up now. Even with my own original code.

I thought (just a while ago) that maybe it was because the script occured before the image elements with those classes/IDs in the flow of the HTML (wasn’t sure if that mattered)… so, I moved the script to the end (before the closing body tag… which I suppose is the more ideal place for them, but I was concerned having the script (and the display swap) AFTER the actual image items might result in a quick flash, as I figured the images would appear and THEN the script would run… but, then in retrospect, that is irrelevant, as both items are (intentionally) set to display:none initially, so they neither would appear (then disappear as the code hit)…

But, still… doesn’t work. This is depressing. I know it’s something REALLY simple.

AWESOME! I just got my original coding method to work.

I think the issue was (partially?) the fact that my ID names were the same as the class names… although I thought the only restriction with IDs is that each ID name is only used on one element (which is was)… not that you can’t use the same name as an existing class…

No matter… it works.

With SVG support, the anim displays, and the fallback image doesn’t appear or push the flow.

With no SVG support, the still only appears… again, not getting pushed by the ‘hidden’ animation.

Wow, that kind of just happened, after two days of going around in circles, trying various variations.

Time to save some backups of this version, and get on with my life!

Hopefully, this sticks…

Cheers!

Argh… Okay, so it’s still having issues on some devices.

Basically, everything is working as intended, except that some devices are still pushing the content down, despite the animation being set to display:none.

From what I can see after many tests, the div is (visibly) empty, yet still getting stretched out as if the item were still inside it.

As best as I can figure this, it seems that the SVG test is ‘passing’, yet the device is unable to graphically render the SVG canvas. Otherwise, if the test failed, it would be displaying the still image.

Works great on desktops/laptops… but so far on an old iTouch and an iPhone, it APPEARS it is passing the SVG support test code (so the still image is not displayed), yet it can’t render the SVG canvas. So, there’s a large blank area where SOME sort of graphic shold be (anim or still image).

So, I guess what that all means, is I need a better means to test the SVG support.

The actual coding of that is way beyond me. The code I got for my current SVG support test was found online.

Anyone know this sort of thing well enough to suggest a better, alternate SVG test?

The SVG that is being displayed (and then animated via GSAP Javascript) is just an SVG tag, with a number of < image > tags containing png images.

But, it seems that the devices either can’t support the SVG tag, or (I think more likely) the < image > tag, since I assume the current test code would certainly cover the SVG tag. How could I re-rig the current SVG support code so it tests for the image tag instead?