What strategies can be used to dynamically insert svg elements without compromising their interactivity?

Here's a thought-provoking question with no definitive answer: We have 3 different svg logos for phone, tablet, and desktop. Each has a hover effect, but there is one special logo that requires a unique hover effect and is wrapped in a link.

I'd like to achieve 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 do you think about this approach?

My initial idea was to use svgsprite and dynamically load the appropriate resource based on media queries, but I couldn't find any solutions or documentation on how to do this.

The simplest solution would be to have 3 inline svg inserts with display:none for unused svgs. This may not be elegant, but it could work. However, updating the logo.svg would require re-inserting the code.

If we consider using an object tag, it's unclear how to set media queries for it. It might also require styling inside the svg itself (hover effects 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>

Another option is to link external stylesheets, although I encountered issues with this. Simply referencing style.css in the object tag did not apply the styles as expected.

I've tried various methods to find the best solution, but so far nothing seems to be ideal or functional:

<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 pure CSS and HTML isn't the way to go, perhaps implementing this through JavaScript could be a viable option. If you have any resources or solutions related to this, please share them.

Answer №1

Personally, I find no issue with swapping the logo using display:none. Here is an example utilizing sprites. The sprites are embedded inline for compatibility with the SO snippet environment, but symbols could also be sourced from external files.

The most reliable method to apply styles in sprites based on different scenarios is through 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>

Answer №2

Using Media Queries along with the SVG as a background-image is a possible solution.

A Different Approach in JavaScript

Inspired by my creation of the <load-file> JSWC Web Component.

I've included code that evaluates the screen width and generates a corresponding file name for "small|medium|large".

The snippet showcased below will consistently show the 628:medium file,
you can experiment with it on this JSfiddle link: 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring and Troubleshooting HTML and JavaScript with Visual Studio Code Debugger

Visual Studio Code Version 1.10.2 Windows 10 I am currently experimenting with VS Code and would like to debug some basic HTML and JavaScript code. The instructional video found at http://code.visualstudio.com/docs/introvideos/debugging mentions that ...

Step-by-step tutorial for making a mesmerizing fade out grunge background

How can I achieve a fading grid background effect? I have experimented with using a conic-gradient for the background, but I am unsure how to make it fade out. background: conic-gradient(from 90deg at 1px 1px,#0000 90deg,grey 0) 0 0/50px 50px; ...

Encountered an error while trying to load resource: server returned a 404 status code (NOT FOUND) when using flask

I am facing an issue with a web application I am currently developing. I am using Python Flask on the server side, and every time I try to run the Python app, I encounter a "Failed to load the resource, 404 page not found" error. Below is the structure of ...

Tutorial on making a pop-up appear on click using jQuery

Below are the attempts I have made: Using jQuery: $("#type_name").click(function(){ $("#add_form").fadeIn(1000); $("#involved_name").val(""); positionPopup('#add_form'); $("#involved_name").focus(); }); Usin ...

Is there a way to eliminate get variables and filename from a URL using JavaScript or jQuery?

I've been researching this issue, but unfortunately, I haven't been able to find a definitive solution for my specific needs. Let's say I have a URL like... How can I extract this URL and remove the "index.php?search=my+search" part so that ...

Switch up the display of table rows with a convenient Toggle Button located right after the

Looking for a way to toggle the visibility of certain rows in an HTML table using a button but having trouble placing the button after the table instead of before. Any suggestions on how to customize this setup? Thanks! /*Use CSS to hide the rows of t ...

When I use the readfile function to display content on my page, it automatically indents the

I am experiencing an issue where the first line of text is indented when I use readfile in php on my page. Is there a simple solution to fix this problem or is it something that must be addressed with more complex measures? Below you can see a snippet of ...

Exploring the implementation of toggling functionality for nested children within <li> elements using jQuery

Unable to get the toggle function working on child nodes. Can someone assist me with this issue? $(document).ready(function() { $('label.tree-toggler').click(function() { $(this).parent().children('ul.tree').toggle(300); }); ...

Changing the hover background color and text color of Material UI Button

I recently developed a custom Appbar component using React.js that includes 3 buttons. I'm looking to enhance the user experience by changing the color scheme when users hover over these buttons. Currently, the background color is set to #3c52b2 and t ...

Generating an HTML table while setting the font size using SQL FOR XML

I have been tasked with creating an SQL statement that generates an HTML table and specifies the font size of its content. I came across some helpful information here. The solution provided in this resource explains how to retrieve XML elements without at ...

What is the best method for transferring data from a submit form in ReactJS to AdonisJS?

Seeking guidance on integrating a ReactJS form with an Adonis API to pass data upon form submission. Snippet from ReactJs file: async handleSubmit(e) { e.preventDefault(); console.log(JSON.stringify(this.state)); await axios({ ...

Providing parameters to a dynamic component within NextJS

I am dynamically importing a map component using Next.js and I need to pass data to it through props. const MapWithNoSSR = dynamic(() => import("../Map"), { ssr: false, loading: () => <p>...</p>, }); Can anyone sugges ...

Combining JWT authentication with access control lists: a comprehensive guide

I have successfully integrated passport with a JWT strategy, and it is functioning well. My jwt-protected routes are structured like this... app.get('/thingThatRequiresLogin/:id', passport.authenticate('jwt', { session: false }), thing ...

Enhance the appearance of the standard black rectangle displaying the messages "No video source" or "No video permissions"

Is there a way to change the styling of the video element that appears as a black rectangle with a strikethrough play button when the user is prompted for permission on Safari? Does it have a specific ID, class, or tag that can be targeted? I'm curre ...

What steps do I need to take in order to establish a connection to a GridFS bucket

I have successfully implemented file uploads using a gridfs bucket. However, I am facing challenges with downloading files. For retrieving files, I need to access the bucket instance that I created within the database connection function: const connectDB ...

What is the best method for conducting comprehensive testing of all projects and libraries within NestJS (nx)?

Our NestJS project has been established with multiple libraries through Nx. We have successfully run tests on individual projects/libraries using the following command: npx nx test lib1 --coverage While this method works well, we are faced with numerous l ...

When the browser window is minimized, the @media CSS will wrap to the bottom line

When the browser has a standard resolution, the layout looks like this: https://i.sstatic.net/tNR6X.png However, on smaller screens, it appears like this: https://i.sstatic.net/U3RnZ.png Is there a way to adjust the positioning of these blocks using @m ...

Assign CSS properties based on the value defined in the component selector in Angular 5

In order to achieve the desired goal outlined below, I am looking to utilize mat-icon in Angular/Material to access material icons. My objective is to dynamically adjust the size of these icons using the ngStyle directive or a more efficient alternative if ...

Manage text, PDF, and image files in a MEAN stack app by uploading and fetching them from a MongoDB database using

I have been working on developing a piece of code that allows users to create a dynamic URL, upload a file by clicking a button on the page, and then download the same file in the same format when revisiting the URL. The functionality is similar to cl1p, b ...

How to choose the desired day within a specific month when creating a calendar from scratch?

Hi there! I need some assistance. I'm currently working on enhancing a calendar by adding an extra feature. The idea is that when the user selects one or more days, those specific day(s) should be highlighted. However, I'm facing an issue where s ...