Beginner Q: Is there a cleaner way to group a list in JS?

Posted on

Problem

I’m looking to highlight some words on a webpage, I’ve grouped them now, but changed the css and html slightly and this seems to have broken it.

For context, looking to add a list of words in JS which would then apply formatting to those words. I changed the p to a span because I wanted them to be an inline-block, which I don’t think is possible as a paragraph; however this has broken it.

$(document).ready(function() {

  function hiliter(word, element) {
    var rgxp = new RegExp("\b" + word + "\b", 'gi'); // g modifier for global and i for case insensitive 
    var repl = '<span class="sketch-highlight">' + word + '</span>';
    element.innerHTML = element.innerHTML.replace(rgxp, repl);

  }

  function hiliteWords(words, element) {
    words.forEach(word => {
      hiliter(word, element);
    });
  }

  //hiliter('dolor', document.getElementById('dolor'));
  hiliteWords(['creo', 'think',
    'mojado', 'wet'
  ], document.getElementById('subs'));
});
span {
  display: inline-block;
  padding: 8px;
  border: 0px white;
  background-color: white;
  font-size: 19px;
  line-height: 1.825;
  color: #000000;
  font-family: Nunito, sans-serif;
}

body {
  margin-left: 1px;
  margin-right: 1px;
}

.sketch-highlight {
  position: relative;
}

.sketch-highlight::before {
  content: "";
  z-index: -1;
  left: 0em;
  top: 0em;
  border-width: 2px;
  border-style: solid;
  border-color: darkblue;
  position: absolute;
  border-right-color: transparent;
  width: 100%;
  height: 1em;
  transform: rotate(2deg);
  opacity: 0.5;
  border-radius: 0.25em;
}

.sketch-highlight::after {
  content: "";
  z-index: -1;
  left: 0em;
  top: 0em;
  border-width: 2px;
  border-style: solid;
  border-color: darkblue;
  border-left-color: transparent;
  border-top-color: transparent;
  position: absolute;
  width: 100%;
  height: 1em;
  transform: rotate(-1deg);
  opacity: 0.5;
  border-radius: 0.25em;
}
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" type="text/css" href="styles.css" />
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Nanum+Brush+Script&family=Nanum+Pen+Script&display=swap" rel="stylesheet">

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

  <body id='subs'>

    <center>

      <span><small>It was, it was. And then in an instant, it wasn't.</small><br>Pues sí, pues sí. Y luego, en un instante, se paró.</span>
      <span><small>- ¿Y por qué Jim no está mojado? - Yo… corrí más.</small><br>Why isn't Jim wet? I...outran it.</span>
      <span><small>No creo que haya llovido. Si no, me dolería la cadera.</small><br>I don't think it rained. My hip would be hurting.</span>


    </center>
  </body>
</head>

</html>

 

Solution

var repl = '<span class="sketch-highlight">' + word + '</span>';

This line can be made a bit cleaner looking by using template literals:

var repl = `<span class="sketch-highlight">${word}</span>`;

span {
  display: inline-block;
  padding: 8px;
  border: 0px white;
  background-color: white;
  font-size: 19px;
  line-height: 1.825;
  color: #000000;
  font-family: Nunito, sans-serif;
}

The CSS rule applies to .sketch-highlight elements too, which I presume is not the desired behavior.

.sketch-highlight spans can be excluded with the :not(…) pseudo-class:

span:not(.sketch-highlight) {

But it’s better to make a new class name for the spans so you don’t need to use :not(…). Example:

<span class='main-text'><small>It was, it was. And then in an instant, it wasn't.</small><br>Pues sí, pues sí. Y luego, en un instante, se paró.</span>
<span class='main-text'><small>- ¿Y por qué Jim no está mojado? - Yo… corrí más.</small><br>Why isn't Jim wet? I...outran it.</span>
<span class='main-text'><small>No creo que haya llovido. Si no, me dolería la cadera.</small><br>I don't think it rained. My hip would be hurting.</span>

.main-text {
  display: inline-block;
  padding: 8px;
  border: 0px white;
  background-color: white;
  font-size: 19px;
  line-height: 1.825;
  color: #000000;
  font-family: Nunito, sans-serif;
}

Currently the highlights are invisible because of their negative z-indexs.

.sketch-highlight::before {
  content: "";
  z-index: -1;

The negative z-indexs place the ::before and ::after pseudo-elements behind the outer spans that have background-colors of white.

In order to get the highlights to be visible, a non-negative z-index can be set on .sketch-highlight:

.sketch-highlight {
  position: relative;
  z-index: 0; // creates a new stacking context that prevents its children from going behind it
}

Putting z-index: 0 in .sketch-highlight creates a stacking context. That prevents .sketch-highlight’s child elements (including ::befores and ::afters) from going behind the container spans.


left: 0em;
top: 0em;

Units such as “em” aren’t necessary when the values are zero, so these declarations can be shortened to:

left: 0;
top: 0;

<body id='subs'>

  <center>

    <span><small>It was, it was. And then in an instant, it wasn't.</small><br>Pues sí, pues sí. Y luego, en un instante, se paró.</span>
    <span><small>- ¿Y por qué Jim no está mojado? - Yo… corrí más.</small><br>Why isn't Jim wet? I...outran it.</span>
    <span><small>No creo que haya llovido. Si no, me dolería la cadera.</small><br>I don't think it rained. My hip would be hurting.</span>

  </center>
</body>

The <center> tag is obsolete in HTML5. Consider using a different tag such as <div> and text-align: center; in CSS.


Results

$(document).ready(function() {

  function hiliter(word, element) {
    var rgxp = new RegExp("\b" + word + "\b", 'gi'); // g modifier for global and i for case insensitive 
    var repl = `<span class="sketch-highlight">${word}</span>`;
    element.innerHTML = element.innerHTML.replace(rgxp, repl);
  }

  function hiliteWords(words, element) {
    words.forEach(word => {
      hiliter(word, element);
    });
  }

  //hiliter('dolor', document.getElementById('dolor'));
  hiliteWords(['creo', 'think',
    'mojado', 'wet'
  ], document.getElementById('subs'));
});
.main-text {
  display: inline-block;
  padding: 8px;
  border: 0px white;
  background-color: white;
  font-size: 19px;
  line-height: 1.825;
  color: #000000;
  font-family: Nunito, sans-serif;
}

body {
  margin-left: 1px;
  margin-right: 1px;
}

.sketch-highlight {
  position: relative;
  z-index: 0;
}

.sketch-highlight::before {
  content: "";
  z-index: -1;
  left: 0;
  top: 0;
  border-width: 2px;
  border-style: solid;
  border-color: darkblue;
  position: absolute;
  border-right-color: transparent;
  width: 100%;
  height: 1em;
  transform: rotate(2deg);
  opacity: 0.5;
  border-radius: 0.25em;
}

.sketch-highlight::after {
  content: "";
  z-index: -1;
  left: 0;
  top: 0;
  border-width: 2px;
  border-style: solid;
  border-color: darkblue;
  border-left-color: transparent;
  border-top-color: transparent;
  position: absolute;
  width: 100%;
  height: 1em;
  transform: rotate(-1deg);
  opacity: 0.5;
  border-radius: 0.25em;
}
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" type="text/css" href="styles.css" />
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Nanum+Brush+Script&family=Nanum+Pen+Script&display=swap" rel="stylesheet">

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

  <body id='subs'>

    <center>

      <span class='main-text'><small>It was, it was. And then in an instant, it wasn't.</small><br>Pues sí, pues sí. Y luego, en un instante, se paró.</span>
      <span class='main-text'><small>- ¿Y por qué Jim no está mojado? - Yo… corrí más.</small><br>Why isn't Jim wet? I...outran it.</span>
      <span class='main-text'><small>No creo que haya llovido. Si no, me dolería la cadera.</small><br>I don't think it rained. My hip would be hurting.</span>

    </center>
  </body>
</head>

</html>

Leave a Reply

Your email address will not be published. Required fields are marked *