skip to Main Content

Using Jinja2 templating engine

<div class="card-footer d-flex justify-content-between">
    <small class="me-2 d-flex gap-2 description-container">
        <span id="description-text" class="description-text">
            {% if photo.description %}
            {{ photo.description }}
            {% endif %}
        </span>
        <span id="dimension-text" class="dimension-text text-muted">
            {% if photo.width and photo.height %}
            (Dimensions: {{ photo.width }} x {{ photo.height }})
            {% endif %}
        </span>
    </small>
    <small class="float-end text-muted text-end">
        {% if photo.category %}
        {{ photo.category }}
        {% endif %}
    </small>
</div>

When the description-text is too long, it makes a new line in the footer and wraps the text to the new line since it can’t fit itself with dimension-text. Because of this, the dimension-text also wraps to the new line to use up the extra space which looks kind of ugly.

Is there a way to find out when there is no more space to fit both the description & dimension texts, and if so, get rid of the dimension-text span? Once there is enough space to fit both on the same line, let the dimension-text re-appear.

enter image description here

2

Answers


  1. Chosen as BEST ANSWER

    After some thinking, I realized the best way of doing this was to just check the width of the footer element and compare it to the total width of its child elements to see if the child elements required more space than what's available.

    Here is my solution:

    <script>
    const whiteSpace = 50;
    const descriptionTexts = document.getElementsByClassName('description-text');
    const dimensionTexts = document.getElementsByClassName('dimension-text');
    const categoryTexts = document.getElementsByClassName('category-text');
    
    function toggleDimensionText() {
        for (let i = 0; i < descriptionTexts.length; i++) {
            const descriptionText = descriptionTexts[i];
            const dimensionText = dimensionTexts[i];
            const categoryText = categoryTexts[i];
            const footer = descriptionText.parentElement.parentElement;
            const footerWidth = footer.offsetWidth;
            let dimensionTextWidth = dimensionText.offsetWidth;
            const descriptionTextWidth = descriptionText.offsetWidth;
            const categoryTextWidth = categoryText.offsetWidth;
    
            if (window.getComputedStyle(dimensionText).display == 'block') {
                if (!enoughSpace(footerWidth, descriptionTextWidth, dimensionTextWidth, categoryTextWidth)) {
                    dimensionText.style.display = 'none';
                }
            }
            if (window.getComputedStyle(dimensionText).display == 'none') {
                dimensionText.style.display = 'block';
                dimensionTextWidth = dimensionText.offsetWidth;
                if (enoughSpace(footerWidth, descriptionTextWidth, dimensionTextWidth, categoryTextWidth)) break;
                else dimensionText.style.display = 'none';
            }
        }
    }
    
    function enoughSpace(footerWidth, descriptionTextWidth, dimensionTextWidth, categoryTextWidth) {
        return footerWidth >= descriptionTextWidth + dimensionTextWidth + categoryTextWidth + whiteSpace;
    }
    
    // Call the toggleDimensionText function initially and whenever the window is resized
    toggleDimensionText();
    window.addEventListener('resize', toggleDimensionText);
    

    This solution uses offSetWidth. The whitespace variable is used to account for the space taken up by things like margins and other "whitespace" in the footer.

    I set the display of the dimensionText back to block and calculated its offset width again because when it's display is none, there is no width. Since I set it back to none if there isn't enough space in the same "frame", there is no flickering in the browser.

    Hope this helps!


  2. In elements with plain text, each line of text as it is displayed in the browser gets its own DOMRect. Because your .description-text box is just plain text, you can get the element’s DOMRects with .getClientRects() and if its .length is greater than 1 (the element has more than one DOMRect), then the text is wrapped. This is very similar to this answer from 2011 (the method still works twelve years later).

    You can then use this to the hide .dimension-text boxes in each footer by looping over all the footers and checking if their .description-text is wrapped. If it is, then change the .dimension-text‘s display CSS style to none, otherwise you can set it to inline (the default for <span> elements). You’ll have to do this process when the DOM first loads and every time the window resizes because text might become wrapped or unwrapped.

    function textIsWrapped(el) {
      return el.getClientRects().length > 1;
    }
    
    function hideLongDimensionSizes() {
      const footers = document.getElementsByClassName('card-footer');
      for (const footer of footers) {
        const desc = footer.querySelector('.description-text');
        const dims = footer.querySelector('.dimension-text');
        dims.style.display = textIsWrapped(desc) ? 'none' : 'inline';
      }
    }
    
    window.addEventListener('resize', hideLongDimensionSizes);
    hideLongDimensionSizes();
    /* example styles */
    .card-footer {
      width: 200px;
      background: red;
      color: white;
      padding: 10px;
      margin: 20px;
    }
    <div class="card-footer d-flex justify-content-between">
      <small class="me-2 d-flex gap-2 description-container">
            <span id="description-text" class="description-text">
                A photo
            </span>
            <span id="dimension-text" class="dimension-text text-muted">
                (Dimensions: 100 x 200)
            </span>
        </small>
      <small class="float-end text-muted text-end">
            Example
        </small>
    </div>
    
    <div class="card-footer d-flex justify-content-between">
      <small class="me-2 d-flex gap-2 description-container">
            <span id="description-text" class="description-text">
                A photo with a really long description that takes up two lines.
            </span>
            <span id="dimension-text" class="dimension-text text-muted">
                (Dimensions: 100 x 200)
            </span>
        </small>
      <small class="float-end text-muted text-end">
            Example
        </small>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search