1

I had to look for the answer to my problem but can't find the solution. I have found some solutions but they using px, not a % what is more difficult to do. I would like to subtract in percentage CSS left value which is 50%.

JS:

document.addEventListener("keydown", function (e) {
    if(e.keyCode == 37){
    console.log("left")
    $('.fa-circle').css('left','-=3%' )
    }
}

CSS:

.fa-circle{
    position: absolute;
    left: 50%;
    top: 50%;
    font-size: 30px;
    transition: all .3s;
}

For every key down (left arrow) the left position of the circle should be subtracted.

e.g. 1st click = left: 47%; 2nd click = left: 44; 3rd click = left: 41%...

2 Answers2

3

You have to parse out the current value and then subtract 3 before putting it back:

document.addEventListener("keydown", function (e) {
    if(e.keyCode == 37){
      console.log("left")
      const currentLeft = parseInt($('.fa-circle').css('left'));
      $('.fa-circle').css('left', (currentLeft - 3) + '%' );
    }
}

EDIT: as pointed out by the OP in the comments, this doesn't work as expected - because jQuery .css('left') returns the value in pixels, even if its been explicitly set as a percentage. jQuery doesn't offer a built-in way to do this - see eg. here.

One suggestion from those answers that works here is to calculate the percentage manually, but multiplying by const currentLeft = 100*(parseInt($('.fa-circle').css('left'))/($("body").width()));. In practice, you can replace "body" by a selector for whatever the closest positioned parent element is.

Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
  • Asking for my background knowledge/best practice efforts, why use `const` over `var` for currentLeft in this function? - also I believe it's uneccesary but would it be better to implicity type cast `currentLeft-3` with toString? (and lastly, currentLeft is missing capital l when setting value) – TCooper Jun 29 '20 at 23:45
  • 1
    Because you never intend to reassign that variable, so it's better style to enforce that, so you will get early errors if you accidentally try to change it later. (Even if you do intend to change it, you should use `let`, `var` is basically obsolete unless you really need your code to run on ancient browsers like IE and aren't transpiling.) – Robin Zigmond Jun 29 '20 at 23:48
  • When you say it like that I get flashbacks to textbooks and it seems painfully obvious. Thanks for clarifying. Good point on `let` > `var`. I do sometimes write for ancient browsers (or clients I can't trust to be off ancient browsers at least), so it's more prominent in my mind than I'd like for most applications. – TCooper Jun 29 '20 at 23:52
  • @TCooper apologies, I only just noticed your other points in your first comment. Thanks for pointing out the typo, that's fixed now. As for explicitly converting the number to a string - you're right that it's unnecessary but more explicit. Usually I prefer being explicit, but in this case I feel the gain is small and doesn't make up for the added boilerplate code. But that's a matter of opinion, I wouldn't say anyone was wrong if they wrote this with the explicit conversion. – Robin Zigmond Jun 30 '20 at 09:17
  • I did a quick edit right after posting that first comment ;) Thanks for weighing in. I'm almost entirely self taught when it comes to javascript, trying to establish what my bad habits are/aren't before I can work on them. – TCooper Jun 30 '20 at 17:38
  • @RobinZigmond Yours code doesn't work well, if we log currentLeft we got this output ```[Log] 960 (index.js, line 10) [Log] 18374 (index.js, line 10) [Log] 352723 (index.js, line 10) [Log] 6772224 (index.js, line 10)``` The circle for every Left Arrow press should be move to left by 3% of current left position – Kamil Rzeszutek Jun 30 '20 at 19:09
  • I can't explain that, there must be something else going on in your code. That's (very approximately) multiplying by 20 each time. Are you sure you copied the code in my answer accurately? – Robin Zigmond Jun 30 '20 at 19:17
  • 1
    Here is my full code https://codepen.io/kamiljx/pen/abdVmvN – Kamil Rzeszutek Jun 30 '20 at 19:25
  • Thanks for sharing, and apologies - it's been a while since I last used jQuery and had forgotten that `.css(...)` will give you the value of the property in *px*, even when you've specified it as a percentage. This is what's messing up the numbers. The best solution, albeit a bit hacky, is to calculate the percentage yourself, by multiplying the px value and dividing by the width of the parent element (which in the case of your codepen in the body, but may not be in your real application). `const currentLeft = 100*(parseInt($('.fa-circle').css('left'))/($("body").width()));` works for me – Robin Zigmond Jun 30 '20 at 20:08
0

Thanks to @RobinZigmond I've found the solution.

    if(e.keyCode == 37){
      console.log("left")
      const currentLeft = parseInt($('.fa-circle').css('left'));
      const percentage = currentLeft - (3*currentLeft)/100
       $('.fa-circle').css('left',  percentage)
      console.log($('.fa-circle').css('left'))
    }
})

The browsers calculate the percentage of screen size to px so we can't to manipulate as %. The @RobinZigmond answer is not good because currentLeft may be 931 and if we add % we got 931% on left.

Firstly we have to parse the value of Left position to int. The second step is very easy to do, We have to calculate the currentLeft - 3% with math.

EDIT: The solution above is incorrect. Why? Using code above we subtract 3% of existing value. For 5 click the left value should be 35% => 672px. Using code above after 5 click we got (1)960px-3% = 931px then (2) 931px -3% ... (5)824px at the end left value is equal to 42.93%.

Correct code:

var fullscreenWidth = window.innerWidth
var widthMinusThreePercent = Math.floor(fullscreenWidth- ( fullscreenWidth- (3*fullscreenWidth) /100))

document.addEventListener("keydown", function (e) {
    if(e.keyCode == 37){
        console.log("left")
        const currentLeft = parseInt($('.fa-circle').css('left'));
        //const percentage = currentLeft - (3*currentLeft)/100
        $('.fa-circle').css('left',  currentLeft - widthMinusThreePercent)
    })