skip to Main Content

I think this is an interesting question to which there is no comprehensive answer.
We have 3 svg logo variants for phone, tablet, desktop. They have a hover, but 3 svg has a special one, which does not allow you to set the same universal hover. And the logo is wrapped in a link.

I would like to implement something similar using CSS and HTML:

<a class="logo" href="index.html">
  <picture>
    <source media="(min-width:1200px)" srcset="logotype-desktop.svg">
    <source media="(min-width:660px)" srcset="logotype-tablet.svg">
      <img class="logo__img" src="logotype-mobile.svg">
  </picture>
</a>

What are your thoughts on this?

The first idea was to somehow use “svgsprite and connect the necessary resource depending on the media – I did not find such solutions and there is nothing like this in the documentation.

The simplest idea is 3 inline inserts and display:none for unused svgs. It seems awkward, but it will work. However, when changing the logo.svg, you need to re-insert inline.

If we consider an object, it is unclear how to set media for it. It is also necessary to either prescribe styles inside svg (for some reason the hover didn’t work for me)

<svg width="74" height="23" viewBox="0 0 74 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
  <![CDATA[  
        path:hover {
        fill: red;
        }
        ]]>
</style>
<path d="M.005 1.549A1.286 1.286 0 011.257.262H8.39c5.057 0 8.385 2.703 8.385 7.13v.06c0 4.846-4.033 7.358-8.802 7.358H2.538v6.801a1.28 1.28 0 01-.754 1.28 1.269 1.269 0 01-1.717-.758 1.28 1.28 0 01-.062-.522V1.549zm8.067 10.968c3.706 0 6.14-1.994 6.14-4.986v-.06c0-3.21-2.394-4.875-5.961-4.875H2.588v9.881l5.484.04zM21.593 1.389a1.282 1.282 0 01.755-1.28 1.268 1.268 0 011.717.758c.056.168.077.346.062.522v20.222a1.28 1.28 0 01-.754 1.28 1.27 1.27 0 01-1.717-.758 1.282 1.282 0 01-.063-.522V1.389zm9.081.03A1.278 1.278 0 0131.926.173h.348a1.535 1.535 0 011.281.737l13.6 17.4V1.36A1.239 1.239 0 0148.389.122c.327 0 .64.13.871.362.231.232.36.546.36.874V21.65a1.14 1.14 0 01-.703 1.092 1.13 1.13 0 01-.449.085h-.129a1.695 1.695 0 01-1.311-.778L33.117 4.24v17.41a1.258 1.258 0 01-1.191 1.247 1.238 1.238 0 01-1.212-1.247V1.42h-.04zm25.264-.03a1.282 1.282 0 01.755-1.28 1.268 1.268 0 011.717.758c.056.168.077.346.062.522v12.295L71.228.55c.262-.271.618-.432.994-.448a1.27 1.27 0 011.222 1.256 1.29 1.29 0 01-.418.898l-7.947 7.897 8.573 10.53c.224.26.348.593.348.937a1.312 1.312 0 01-.838 1.191 1.228 1.228 0 01-1.497-.493L63.3 11.859l-4.828 4.846v4.886a1.27 1.27 0 01-.78 1.17 1.259 1.259 0 01-1.648-.685 1.27 1.27 0 01-.096-.485V1.389h-.01z" fill="#fff"/>
</svg>

or there is an option to connect external styles, but I couldn’t figure it out. It seems to have indicated a link to its style.css, but styles were also not applied.

I tried to come to a decision that would be ideal, but it seems this is unacceptable/does not work:

<a class="logo" href="index.html">
  <picture>
    <source media="(min-width:1200px)" srcset="logotype-desktop.svg">
    <source media="(min-width:660px)" srcset="logotype-tablet.svg">
    <object class="logo__img" data="logotype-mobile.svg" type="image/svg+xml">
  </picture>
</a>

If we discard the attempt to do everything in pure CSS and HTML, then how to implement this through JS (I think this is a topic of a separate question, I will be grateful for links to solutions)?

2

Answers


  1. Frankly, I don’t see why you consider switching the logo via display:none as awkward. Here is an implementation with sprites. The sprites are defined inline to accomodate the SO snippet environment, but you could easily reference symbols in external files.

    The most stable way to set styles in sprites depending on use cases is via CSS variables.

    .logo use {
      display: none;
    }
    
    .logo:hover use {
      --fill-1: red;
      --fill-2: green;
    }
    
    .logo .logotype-mobile {
      display: inline;
    }
    
    @media screen and (min-width: 660px) {
      .logo .logotype-mobile {
        display: none;
      }
      .logo .logotype-tablet {
        display: inline;
      }
    }
    
    @media screen and (min-width: 1200px) {
      .logo .logotype-tablet {
        display: none;
      }
      .logo .logotype-desktop {
        display: inline;
      }
    }
    <svg width="0" height="0">
      <symbol id="on-mobile" viewBox="0 0 24 24">
        <path d="M1,1h22v22H1z" style="fill: var(--fill-1, black)" />
      </symbol>
      <symbol id="on-tablet" viewBox="0 0 24 24">
        <path d="M1,20h22L12,2z" style="fill: var(--fill-1, black)" />
      </symbol>
      <symbol id="on-desktop" viewBox="0 0 24 24">
        <circle r="11" cx="12" cy="12" style="fill: var(--fill-2, black)" />
      </symbol>
    </svg>
    
    <a class="logo" href="index.html">
      <svg width="32" height="32">
        <use class="logotype-mobile" href="#on-mobile" />
        <use class="logotype-tablet" href="#on-tablet" />
        <use class="logotype-desktop" href="#on-desktop" />
      </svg>
    </a>
    Login or Signup to reply.
  2. It can probably be done with Media Queries and the SVG as background-image.

    Native JavaScript solution

    Adapted from my <load-file> JSWC Web Component.

    Added code to check screenWitdh and construct a "small|medium|large" src file name.

    The SO snippet below will always display 628:medium file,
    here is a JSfiddle to play with: https://jsfiddle.net/WebComponents/jp3ue6Lx/

    <load-file replaceWith 
               sizes="600:medium;1200:large"
               src="//svg-cdn.github.io/file-[size].svg"   
               ></load-file>
    
    <script>
      customElements.define("load-file", class extends HTMLElement {
        async connectedCallback(
          shadowRoot = this.shadowRoot || this.attachShadow({mode:"open"})
        ) {
          let srcsize = (this.getAttribute("sizes")||"0:small")
                          .split(";")
                          .reduce((srcsize, size) => {
                            let [px, sizename] = size.split(":");
                            return (window.innerWidth > ~~px) ? sizename : srcsize;
                          }, "small");
          let src = this.getAttribute("src").replace("[size]",srcsize);
          console.log(window.innerWidth,srcsize,src);
          shadowRoot.innerHTML = await (await fetch(src)).text()
          shadowRoot.append(...this.querySelectorAll("[shadowRoot]"))
          this.hasAttribute("replaceWith") && this.replaceWith(...shadowRoot.childNodes)
        }
      })
    </script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search