Home > Mobile >  Decrement font-size on condition, why is my recursive function not working?
Decrement font-size on condition, why is my recursive function not working?

Time:04-23

I have a <p> element inside a parent <div> container. The parent container is sized with width and height as a % of the viewport. Upon window-resize, I want to decrement the font-size of <p> until the height of the <p> element is less than 40% of the viewport height, which means the text will fit nicely into the parent container.

What's wrong with my function below?

The error I am getting is 'maximum call stack size exceeded'. I know that must be because the base case is not evaluating to true. However I don't understand why not.

I've run these various tests to try to debug without success:

  • Does adjusting font-size through my fontSize variable work: yes
  • Does adjusting font-size impact height of <p> element: yes
  • Can I adjust font-size multiple times and see decreased <p> element size in the console: yes

The function:

<script>
    const pElement = document.getElementById('actualAboutTxt');
    const style = window.getComputedStyle(pElement, null).getPropertyValue('font-size');
    var fontSize = parseFloat(style);

    function decrementFont () {
        if(pElement.scrollHeight <= (window.innerHeight * 0.4)) {
            // do nothing
        } else {
            pElement.style.fontSize = (fontSize - 1)   "px";
            decrementFont();
        };
    };

    addEventListener("load", () => {
        decrementFont();
    });

    addEventListener("resize", () => {
        decrementFont();
    });
</script>

EDIT 1: Update with the HTML and CSS (anonymised some urls):

<section id="mainSection">
        <div >
            <button id="backToFilter" onclick="window.location.href='<link to my url>';">&#8634 back to filter</button>
        </div> 
        <video id="background-video" autoplay loop muted poster="<link to my poster img>">
            <source src="<link to my video>">
        </video>
        <div id="aboutText">
            <h1>Practice makes perfect</h1>
            <p id="actualAboutTxt">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur ultrices enim id leo commodo, ac commodo dolor laoreet. Quisque eget facilisis dui. Ut sit amet dui ultrices, ultrices eros ut, auctor purus. Nulla bibendum velit in rhoncus rutrum.<br><br>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur ultrices enim id leo commodo, ac commodo dolor laoreet. Quisque eget facilisis dui. Ut sit amet dui ultrices, ultrices eros ut, auctor purus. Nulla bibendum velit in rhoncus rutrum.<br><br>  
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur ultrices enim id leo commodo, ac commodo dolor laoreet. Quisque eget facilisis dui. Ut sit amet dui ultrices, ultrices eros ut, auctor purus. Nulla bibendum velit in rhoncus rutrum.</p>
            <button id="firstBtn" onclick="window.location.href='<link to myurl';">Start practicing</button>
        </div>
</section>

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    font-family: 'Archivo', arial; 
}

body {
    display: flex;
    flex-direction: column;
    align-items: center;
}

#mainSection {
    position : relative;
    width: 100vw;
    height: 90vh;
    overflow: hidden;
}

.backBtnDiv {
    width: 100%;
    margin-top: 10px;
    margin-bottom: 10px;
    position: absolute;
    top: 0;
    display: flex;
    justify-content: center;
}

#backToFilter {
    background: transparent;
    border: none;
    font-size: 12px;
    color: white;
}

#backToFilter:hover {
    cursor: pointer;
}

#aboutText {
    position: absolute;
    left: 5%;
    top: 50%;
    transform: translateY(-50%);
    background-color: rgba(255, 255, 255, 0.5);
    height: 60%;
    width: 40%;
    border-radius: 10px;
}

h1 {
    margin-top: 5%;
    margin-left: 5%;
    margin-right: 5%;
    margin-bottom: 5%;
}

#actualAboutTxt {
    margin-bottom: 5%;
    margin-left: 5%;
    margin-right: 5%;
    font-size: 15px;
}

#firstBtn {
    position: absolute;
    bottom: 5%;
    left: 50%;
    transform: translateX(-50%);
    height: 7.5vh;
    width: 75%;
    border-radius: 5px;
    border-color: transparent;
    background-color: rgb(77, 5, 232);
    color: white;
    font-size: 17px;
    font-weight: bold;
}

#firstBtn:hover {
    cursor: pointer;
    background-color: #9bc969;
}

#background-video {
    object-fit: cover;
    object-position: center;
    height: 100%;
    width: 100%;
    position: absolute;
    left: 0;
    right: 0;
    z-index: -1;
}
@media only screen and (max-width: 1000px) {
#aboutText {
    left: 50%;
    transform: translate(-50%, -50%);
    top: 50%;
    height: 80%;
    width: 80%;
    border-radius: 5px;
    }
}

EDIT 2: A solution that kind of works:

Use a double recursive function to keep the <p> element between two vh values. Decrement font if the element is too high, increment font if the element is not heigh enough.

Code:

<script>
    const pElement = document.getElementById('actualAboutTxt');
    const style = window.getComputedStyle(pElement, null).getPropertyValue('font-size');
    var fontSize = parseFloat(style);

    function decrementFont () {
        if(pElement.scrollHeight > (window.innerHeight * 0.30) && pElement.scrollHeight < (window.innerHeight * 0.42)) {
            return;
        } else if (pElement.scrollHeight > (window.innerHeight * 0.42)) {
            pElement.style.fontSize = (--fontSize)   "px";
            decrementFont();
        } else if (pElement.scrollHeight < (window.innerHeight * 0.35)) {
            pElement.style.fontSize = (  fontSize)   "px";
            decrementFont();
        };
    };

    addEventListener("load", () => {
        decrementFont();
    });

    addEventListener("resize", () => {
        decrementFont();
    });
</script>

CodePudding user response:

This snippet is an example of non-recursive solution as asked for by the OP. There is no HTML (at present), so it will not work.

Additionally, the code may not ever satisfy the condition, so the loop may run forever.

Using recursion for an non-recursive task is not ideal. You are creating an unnecessary stack when you use recursion here.

const pElement = document.getElementById('actualAboutTxt');
const style = window.getComputedStyle(pElement, null).getPropertyValue('font-size');
var fontSize = parseFloat(style);

function decrementFont() 
{
  let fontOK = false;
  do
  {
    if (pElement.scrollHeight > (window.innerHeight * 0.30) && pElement.scrollHeight < (window.innerHeight * 0.42)) 
    {
      fontOK = true;
    } 
    else if (pElement.scrollHeight > (window.innerHeight * 0.42)) 
    {
      pElement.style.fontSize = (--fontSize)   "px";
    } 
    else if (pElement.scrollHeight < (window.innerHeight * 0.35)) 
    {
      pElement.style.fontSize = (  fontSize)   "px";
    }
  }
  while(!fontOK);
}

addEventListener("load", () => {
  decrementFont();
});

addEventListener("resize", () => {
  decrementFont();
});

CodePudding user response:

So as I understand here is a problem.

if(pElement.scrollHeight <= (window.innerHeight * 0.4)) {
            // do nothing
        } 

so if height will be less or equal to whatever you want then this recursion should end yes? this is a point of recursion and if you will not write a break; it will continue so instead of writing // do nothing comment you should write a break; try this end and see if it works.

  • Related