What is the best method for utilizing the CSS :target selector in order to generate a versatile modal box?

I am looking for a way to display my vast collection of proverbs from an endangered language without overcrowding the page. I have implemented a modal box solution using CSS :target selector, which expands a hidden div element when clicked on. However, I need this functionality to work for each individual proverb without having to create unique classes or IDs for each one. Currently, only the first div box expands when a proverb is clicked in the middle of the list. Is there a way to achieve this for all proverbs without creating hundreds of unique expandable divs?

Below is the code snippet I have been using:

#modalBox {
  display: block;
  position: relative;
  text-align: left;
  overflow: hidden;
  background: #ffffff;
  transition: all 0.4s;
  padding: 5px;
  margin-bottom: 2rem;
  height: 2.5rem;
  width: 100%;
  max-width: 800px;
}

#modalBox:target {
  height: 13.5rem;
}
<div class="proverbs">
  <div id="modalBox">
    <a href="#modalBox"> A (g)attë mbrèšarolë facë i (g)attarièddë cëcatë.</a>
    <p id="data"><b>IPA:</b> a atːə mˌbɾɪʃəˈɾolə fat͡ʃ i ˈatːaɾiˌɛdːə t͡ʃə katʰ</p>
    <p id="data"><b>Italian:</b> La gatta frettolosa fa i gattini ciechi.</p>
    <p id="data"><b>English:</b> The hasty cat makes blind kittens.</p>
    </p>
    <a href="#" class="modalclose">&times;</a>
  </div>
</div>

Answer №1

To create this effect, there are numerous CSS-first methods that don't heavily rely on Javascript.

Surprisingly, one approach doesn't even heavily depend on CSS; it's an HTML-first solution.

Using the details / summary elements provide excellent semantic markup for displaying this type of information.


Here is a functional example:

.modalBox {
  display: block;
  position: relative;
  width: min(98%, 800px);
  padding: 5px;
  overflow: hidden;
}

.modalBox summary {
  font-style: italic;
  cursor: pointer;
}

.modalBox p {
  transform: translateY(30vh);
  transition: transform 0.3s linear;
}

.modalBox[open] p {
  transform: translateY(0);
}
<div class="proverbs">
  <details class="modalBox">
    <summary> A (g)attë mbrèšarolë facë i (g)attarièddë cëcatë.</summary>
    <p data-lang="ipa"><b>IPA:</b> a atːə mˌbɾɪʃəˈɾolə fat͡ʃ i ˈatːaɾiˌɛdːə t͡ʃə katʰ</p>
    <p data-lang="it"><b>Italian:</b> La gatta frettolosa fa i gattini ciechi.</p>
    <p data-lang="en"><b>English:</b> The hasty cat makes blind kittens.</p>
  </details>
  
  <details class="modalBox">
    <summary> A (g)attë mbrèšarolë facë i (g)attarièddë cëcatë.</summary>
    <p data-lang="ipa"><b>IPA:</b> a atːə mˌbɾɪʃəˈɾolə fat͡ʃ i ˈatːaɾiˌɛdːə t͡ʃə katʰ</p>
    <p data-lang="it"><b>Italian:</b> La gatta frettolosa fa i gattini ciechi.</p>
    <p data-lang="en"><b>English:</b> The hasty cat makes blind kittens.</p>
  </details>
  
  <details class="modalBox">
    <summary> A (g)attë mbrèšarolë facë i (g)attarièddë cëcatë.</summary>
    <p data-lang="ipa"><b>IPA:</b> a atːə mˌbɾɪʃəˈɾolə fat͡ʃ i ˈatːaɾiˌɛdːə t͡ʃə katʰ</p>
    <p data-lang="it"><b>Italian:</b> La gatta frettolosa fa i gattini ciechi.</p>
    <p data-lang="en"><b>English:</b> The hasty cat makes blind kittens.</p>
  </details>
</div>


For more information:

Answer №2

Featuring over 100 proverbs that require JavaScript functionality. In this scenario, an array of objects is utilized to populate the content upon user interaction with either the #next or #back buttons. The data itself is the only element that needs modification:

const proverbs = [
  {
    main: `A (g)attë mbrèšarolë facë i (g)attarièddë cëcatë.`,
    ipa: `a atːə mˌbɾɪʃəˈɾolə fat͡ʃ i ˈatːaɾiˌɛdːə t͡ʃə katʰ`,
    it: `La gatta frettolosa fa i gattini ciechi.`,
    en: `The hasty cat makes blind kittens.`
  },...
];
/*
Data structure follows [{main: 'first line', ipa: 'line of IPA notation', it: 'Italian translation',
 en: 'English translation'}, {second proverb}, {third proverb},...]
*/

While the utilization of #id is due to the preference of the HTMLFormElement interface which accepts references based on #id, [name], or index -- #id was chosen as it simplifies CSS selector writing. With a single modal catering to an endless list of compact proverbs, using #id should not pose any issues, and in case they do, the [name] attribute can be utilized instead.

Further details are elaborated within the example code comments

// Referencing <form>
const UI = document.forms.UI;
// Array comprising proverbs and translations
const proverbs = [
  {main: `A (g)attë mbrèšarolë facë i (g)attarièddë cëcatë.`,
   ipa: `a atːə mˌbɾɪʃəˈɾolə fat͡ʃ i ˈatːaɾiˌɛdːə t͡ʃə katʰ`,
   it: `La gatta frettolosa fa i gattini ciechi.`,
   en: `The hasty cat makes blind kittens.`},
   {main: `010101010101010101010101010101010101010101`, ipa: `02`, it: `03`, en: `04`},
   {main: `1111111111111111111111111111111111111111111111111`, ipa: `12`, it: `13`, en: `14`},
   {main: `2121212121212121212121212121212121212121212121`, ipa: `22`, it: `23`, en: `24`},
   {main: `3131313131313131313131313131313131313131313131`, ipa: `32`, it: `33`, en: `34`},
   {main: `4141414141414141414141414141414141414141414141`, ipa: `42`, it: `43`, en: `44`},
   {main: `5151515151515151515151515151515151515151515151`, ipa: `52`, it: `53`, en: `54`}
];
// Counter definition
let count = 0; 
// Binding <form> to click event
UI.onclick = clickHandler;
// Click event handler automatically passes Event Object
function clickHandler(e) {
  // Referencing <dialog>
  const modal = document.querySelector('.proverbs');
  // Identifying what the user clicked
  const clk = e.target;
  // Referring all <button>s and <fieldset>
  const IO = this.elements;
  // Opening <dialog> if #open is clicked
  if (clk.matches('#open')) {
    clk.style.display = 'none';
    modal.showModal();
  }
  // Closing <dialog> if #close is clicked
  if (clk.matches('#close')) {
    IO.open.style.display = 'inline-flex';
    modal.close();
  }
  /*
  Upon clicking #next...
  ...increase counter...
  ...if counter exceeds length of proverbs array...
  ...reset counter to 0 (starting again)...
  ...call move() with updated count and IO references
  */
  if (clk.matches('#next')) {
    ++count;
    if (count > (proverbs.length-1)) count = 0;
    move(count, IO);
  }
  // Following similar logic for #back button
  if (clk.matches('#back')) {
    --count;
    if (count < 0) count = proverbs.length -1;
    move(count, IO);
  }
}
// Passing counter and form control reference (IO) 
function move(i, fc) {
  // Referencing <ul>
  const list = document.querySelector('.list');
  // New content string for <legend>
  const main = `<legend>${proverbs[i].main}</legend>`;
  // String for content of <ul>
  const items = `
        <li><b>IPA: </b>${proverbs[i].ipa}</li>
        <li><b>Italian: </b>${proverbs[i].it}</li>
        <li><b>English: </b>${proverbs[i].en}</li>`;
  // Clearing existing <legend> and <li>
  fc.content.firstElementChild.remove();
  list.replaceChildren();
  // Inserting new htmlStrings
  fc.content.insertAdjacentHTML('afterbegin', main);
  list.insertAdjacentHTML('beforeend', items);
}
@import url('https://fonts.googleapis.com/css2?family=Oswald:wght@300&family=Raleway:wght@500&display=swap');

html {
  font: 500 2ch/1.2 'Oswald'
}

dialog {
  position: relative;
  padding-top: 25px;
  border-radius: 8px;
  box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, 
              rgba(0, 0, 0, 0.23) 0px 3px 6px;
}

#content {
  border-radius: 4px;
}

legend {
  font-family: 'Raleway';
  font-weight: 900;
  margin-bottom: -8px;
}

#close {
  position: absolute;
  right: 4px;
  top: 4px;
  height: 1rem;
  font-size: 1.2rem;
}

ul {
  margin-left: 0px;
}

li {
  margin-bottom: 8px;
}

button {
  display: inline-flex;
  align-items: center;
  border: 2px outset rgb(227, 227, 227);
  border-radius: 4px;
  font: inherit;
  font-variant: small-caps;
  cursor: pointer;
}

.btn {
  float: right;
}

#back {
  border-top-left-radius: 4px;
  border-bottom-left-radius: 4px;
  border-top-right-radius: 0px;
  border-bottom-right-radius: 0px;
}

#next {
  border-top-left-radius: 0px;
  border-bottom-left-radius: 0px;
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
}
<form id='UI'>
  <button id='open' type='button'>Open</button>
  <dialog class="proverbs">
    <button id="close" type='button'>&times;</button>
    <fieldset id='content'>
      <legend>A (g)attë mbrèšarolë facë i (g)attarièddë cëcatë.</legend>
      <ul class='list'>
        <li><b>IPA: </b>a atːə mˌbɾɪʃəˈɾolə fat͡ʃ i ˈatːaɾiˌɛdːə t͡ʃə katʰ</li>
        <li><b>Italian: </b>La gatta frettolosa fa i gattini ciechi.</li>
        <li><b>English: </b>The hasty cat makes blind kittens.</li>
      </ul>
      <button id='next' class='btn' type='button'>Next</button>
      <button id='back' class='btn' type='button'>Back</button>
    </fieldset>
  </dialog>
</form>

Answer №3

If you're looking for a cleaner way to achieve this without relying heavily on JavaScript, I have a vanilla approach that might interest you. Instead of directly targeting specific ids, we can utilize class names and allow the browser to determine which clicked element corresponds to which id.

This JavaScript solution dynamically assigns incremental ids (e.g., modalBox0, modalBox1, etc.) to each modal box div and generates corresponding links (e.g., href='#modalBox0', href='#modalBox1', etc.).

const modals = document.querySelectorAll('.modalBox');

modals.forEach((modal, index) => {
  const id = `modalBox${index}`;
  modal.id = id
  const link = modal.querySelector('a');
  link.setAttribute('href', `#${id}`)
})
.modalBox {
  display: block;
  position: relative;
  text-align: left;
  overflow: hidden;
  background: #ffffff;
  transition: all 0.4s;
  padding: 5px;
  margin-bottom: 2rem;
  height: 2.5rem;
  width: 100%;
  max-width: 800px;
}

.modalBox:target {
  height: 13.5rem;
}
<div class="proverbs">
  <div class="modalBox">
    <a href="#"> A (g)attë mbrèšarolë facë i (g)attarièddë cëcatë.</a>
    <p id="data"><b>IPA:</b> a atːə mˌbɾɪʃəˈɾolə fat͡ʃ i ˈatːaɾiˌɛdːə t͡ʃə katʰ</p>
    <p id="data"><b>Italian:</b> La gatta frettolosa fa i gattini ciechi.</p>
    <p id="data"><b>English:</b> The hasty cat makes blind kittens.</p>
    <a href="#" class="modalclose">&times;</a>
  </div>

  <div class="modalBox">
    <a href="#"> A (g)attë mbrèšarolë facë i (g)attarièddë cëcatë.</a>
    <p id="data"><b>IPA:</b> a atːə mˌbɾɪʃəˈɾolə fat͡ʃ i ˈatːaɾiˌɛdːə t͡ʃə katʰ</p>
    <p id="data"><b>Italian:</b> La gatta frettolosa fa i gattini ciechi.</p>
    <p id="data"><b>English:</b> The hasty cat makes blind kittens.</p>
    <a href="#" class="modalclose">&times;</a>
  </div>
</div>

Check out the jsFiddle here

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

Issue with Bootstrap carousel not centered on the page

Currently working on a carousel using bootstrap. The goal is to display 5 images at a time and have it advance by 1 slide each time. The main issue I'm facing right now is that the elements are not properly positioned within the container, and the tr ...

Difficulty with Vue.js updating chart JS label names

I have been working with Vue JS and implementing a chart in my single page application. However, I am encountering difficulties updating the Legend and despite numerous attempts and searches, I am unable to get it to update. Any assistance in correcting my ...

Is it possible to automatically mute an HTML 5 video when closing the modal?

Is there a way to pause a video that plays in a modal and continues playing in the background when the modal is closed? I am using the Materialize library. <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> <!-- Compiled ...

The #each helper in Handlebars is used to iterate over an array

I have a function that generates an array as output. I am looking for a way to iterate over this array using the each method. Can anyone provide guidance on how to achieve this? Consider if the handlebars helper produces the following array: details: [{ ...

The functionality of the bootstrap Dropdown multiple select feature is experiencing issues with the Onchange

Creating a Bootstrap Multiple Select Drop Down with dynamically retrieved options from a Database: <select size="3" name="p" id="p" class="dis_tab" multiple> <?php echo "<option>". $row['abc'] ."</option>"; //Fetching option ...

The checkbox is not updating as anticipated

I'm currently developing a basic widget that allows the user to change the value of either the check box OR the entire div by selecting them. Below is the code I have implemented: $(document).ready(function() { $(document).on("click", ".inputChec ...

In Python 2.7, we can utilize scraping techniques along with the 're' library to extract float numbers from a given string. By using the '

I just scraped this content import re import urllib from BeautifulSoup import BeautifulSoup After scraping, I have results like this (printed numbers_in_mill.text): 9.27[7] 9.25[8] 10.17[9] 10.72[10] How can I modify these results to get: 9. ...

turning every input field's border to red if none of them were filled out at least once

I struggle with javascript and need some help. I have a form with multiple input fields, and I want to ensure that the user fills in at least one of them. I found code that triggers an alert message if the user does not fill in any fields, but I would pref ...

I'm seeking a way to access the input element within the InputGroup component of BlueprintJs in my

The BluePrintJS React InputGroup component offers a convenient user interface for modern applications. However, it does not provide direct access to the internal <input> element. There are two primary reasons why I need to access the input element: ...

Executing Cascading Style Sheets (CSS) within JQuery/Javascript

I've been encountering a problem with my website. I have implemented grayscale filters on four different images using CSS by creating an .svg file. Now, I'm looking to disable the grayscale filter and show the original colors whenever a user clic ...

Solving the problem of Hover Effects in CSS

I am struggling to get the nav-link to be blue in color with a dark-blue hover effect. I managed to set the color correctly, but for some reason, the hover effect is not working. Can anyone help me figure out what the issue might be? Additionally, does any ...

Interact with an external JavaScript function using a button within a web application

I have a JavaScript file called dmreboot_service.js in my /js folder. By running this file with the command node /js/dmreboot_service.js, it successfully triggers a direct method in Azure. My goal is to be able to run this function or file when a button o ...

Troubleshooting a hover problem in CSS navigation bar

Having some trouble with the CSS menu on my website click here. I've tried adjusting the code, but can't seem to get all the menu levels to line up properly. As a beginner in CSS, I'm sure I'm overlooking something simple. When hovering ...

Creating dynamic links between two cells of two HTML tables within an HTML email using JavaScript

A recent project requires the creation of HTML-based emails with tables for each automation script within the test automation framework. Additionally, there is a request for an extra HTML table to provide a quick overview. The cells in the first column of ...

Steps to bold a specific word within a div on react native

Hey there! I'm working with the code below: getDescription = () => { return( <div className="Description">{this.props.mytext + ': ' + this.name} </div> ) } Is it possible to bold only the specific te ...

Different ways to display an HTML page in a well by utilizing a div tag and jQuery from a side menu

Check out my Tutorial Page! Currently, I am working on a simple tutorial page utilizing bootstrap 3. My goal is to showcase the HTML file content within the well container on the right side of the page. However, I am facing challenges as I do not want to ...

unable to submit Angular form via post method

I'm encountering an issue with the code I wrote in HTML. The error message says, "The page you are looking for cannot be displayed because an invalid method (HTTP verb) is being used." This is how my HTML code looks: <form name="payment" action ...

What is causing the divs to not stretch across the entire width of the parent div?

Interactive Code Example: Snippet: <div style="width: 100%; overflow: hidden; height: 65px; background: #00CC00;"> <div style="width: 60%; overflow: hidden; float: left; background: #3074A3; color: #EDEDED; height: 65px; text-align: center; ...

Uploading Multiple Files Using HTML5 and AJAX

I recently stumbled upon this simple plain JavaScript AJAX upload code (apparently jQuery's $.post doesn't work properly with HTML5 for some reason), /* If you want to upload only a file along with arbitrary data that is not in the fo ...

What is the reason this switch statement functions only with one case?

Why is the switch statement not functioning properly? It seems to correctly identify the values and match them with the appropriate case, but it only works when there is a single case remaining. If there are multiple cases to choose from, nothing happens. ...