Showing posts with label css3. Show all posts
Showing posts with label css3. Show all posts

Wednesday, September 19, 2018

Reverse slider when swiped down

Leave a Comment

I followed this article for a vertical swipeable cards slider.

This question has two parts.

1. I cant understand on how to reverse the direction of slider when swiped down?

Here is the relevant codepen - https://codepen.io/bmarcelino/pen/vRYPXV

The relevant function to update the cards

function updateUi() {     requestAnimationFrame(function(){         elTrans = 0;         var elZindex = 5;         var elScale = 1;         var elOpac = 1;         var elTransTop = items;         var elTransInc = elementsMargin;          for(i = currentPosition; i < (currentPosition + items); i++){             if(listElNodesObj[i]){                 listElNodesObj[i].classList.add('stackedcards-bottom', 'stackedcards--animatable', 'stackedcards-origin-bottom');                  listElNodesObj[i].style.transform ='scale(' + elScale + ') translateX(0) translateY(' + (elTrans - elTransInc) + 'px) translateZ(0)';                 listElNodesObj[i].style.webkitTransform ='scale(' + elScale + ') translateX(0) translateY(' + (elTrans - elTransInc) + 'px) translateZ(0)';                 listElNodesObj[i].style.opacity = elOpac;                 listElNodesObj[i].style.display = 'block';                 listElNodesObj[i].style.zIndex = elZindex;                  elScale = elScale - 0.04;                 elOpac = elOpac - (1 / items);                 elZindex--;             }         }      });  }; 

I am not particularly well versed in Javascript.
As of now the slider moves in only one direction when swiped - forward. I am looking to understand an implementation of adding the backward movement to the slider.

2. Regarding performance

Also, requestAnimationFrame really helps out in providing a smooth experience while swiping. But is there a limit as to how many cards should be in DOM? I will be calling an API service to get the contents, since it will return media, so will simply setting opacity to 0 help out in any way reducing memory use?

The author argues that removing DOM would force the browser to repaint, which can impact performance substantially? But isn't that virtual list do? What is the performance to cost ratio in such scenarios?

2 Answers

Answers 1

This is not going to be a complete answer but seeing as no one else has responded I'll give answering part 1 of your question a shot. Note that this is just an example to help you understand how to make the cards go backwards not a production ready solution.

To rewire the "Top" button to go backwards, you just need to make the following changes:

  • In onSwipeTop() change currentPosition = currentPosition + 1; to currentPosition = currentPosition - 1;
  • Also in onSwipeTop() change transformUi(0, -1000, 0, topObj); to transformUi(0, 0, 0, topObj);. This hides the card going up animation.
  • In updateUi() change i < (currentPosition + items) to i <= (currentPosition + items). This fixes a bug where only two of the three cards are updated.

Now try clicking Left or Right a couple times then click Top a couple times. Each time you click Top you should see a card come back.

Presumably you'll want to make a new button "Bottom" instead of rewiring "Top" and you'll probably also want to put limits on changes to currentPosition so you can't go beyond the first/last card but this should at least get you started.

I hope this helps.

Answers 2

Reversing the slider

Following is a very brief explanation of how the script works, including a suggestion for getting it to reverse the direction and 'unswipe' cards. The reverse direction method was inspired by Rocky's excellent answer - he deserves full credit for the idea.

  1. Once the document is loaded the script gets a list of all available cards. In your example the cards are hard coded elements in the DOM, and the list of cards, listElNodesObj, is a list of those elements. This is important to remember: the cards are not an abstraction, they are fundamentally elements within the page. When you add media and data to your cards you will have to do so by attaching it to elements in the DOM (e.g. with data attributes).

  2. The script gets the current card index called currentPosition; to begin with this is the top card. It then displays the current card and the two cards behind it (currentPosition + 1 and currentPosition + 2).

  3. On an input the card is appropriately animated to fly off the left, right or top. The current card index is incremented by one, advancing by one into the stack. The new current card and the two cards behind it are displayed.

At the moment all actions - swipe left, right and top - all advance into the stack. To reverse the direction you need to listen for a new action (or repurpose a current one such as swipe top), and on that action the current card index is decremented by 1. Add a check for less than zero. currentPosition = Math.max( 0, currentPosition - 1 );

Rocky has answered with an excellent solution that implements this.

Now this implementation begins with all cards already present in the DOM. You appear to want to update your stack of cards from a backend API. To do this you need a way of popping the card off one end and adding a new one on the other end when swiping. As stated above your list of cards is tied very closely to the DOM so you will need to abstract it a little to achieve this. Create a list of elements that you fill from your API and populate your initial document with it (instead of the other way around). When you swipe, whether forwards or back, pop an element off the receding end and add a new element, populated from your API, to the advancing end. Interestingly both your list size and your current position will always stay the same.

If your current position is always one back from the top-most card, and the last card in the stack is one more than the last visible card, you will always have a card ready to animate into view.

Performance

A slight clarification of terms here: Altering something like opacity causes a repaint, removing an element from the DOM, whether soft or hard removal, causes a reflow. Repaints are expensive because the browser must check the visibility of every element in the DOM; reflows are even more expensive because the layout must be recalculated. See What's the difference between reflow and repaint?

There are two ways you could limit the number of cards in the DOM. You could set display: none which leaves it in memory and the DOM, but prevents the browser from considering it when reflowing or repainting. Or you could use parent.appendChild(child) to add a card and parent.removeChild(child) to remove the card, ensuring that no reference to that element exists in JavaScript once it's removed, and once the garbage collector runs the removed element will be physically removed from memory. Both will trigger a reflow. Elements with opacity: 0 will remain fully in the DOM for reflowing and repainting.

As to what gives the best performance: changing the opacity or removing from memory, that really depends on your implementation. I can give you a few relevant pointers though.

Memory constraints "Is there a limit as to how many cards should be in DOM?" Absolutely, but this depends on your data. If you have a very small total amount of cards you could indeed load them all at the beginning and hide swiped ones with opacity: 0 or display: none. The animation fluidity might even be improved (see point on animation blocking computations below). The performance difference purely from higher memory use will almost certainly be unnoticeable as modern browsers have oodles of memory and will stop your script well before it needs pagefile or swap. If you really will have such a huge DOM in memory that performance would noticeably degrade, your content download time would be a much bigger issue.

However, much more to the point, you rightly ask if removing or adding elements is the whole point of a virtual list. Why keep an element in memory if you will never access it again, or why load an element that is so far down the list it may never be reached. Indeed you state that you will be accessing content from an API which strongly implies you'll be accessing the card content one at a time. Waiting till you have all the content from your API may take a very noticeable length of time; as you already seem to be aware it would provide a better experience to only access the cards that you need to fill a fixed size list. (If you intend to reverse the direction of the slider then you should keep at least one swiped card in memory so that when swiping back you aren't ruining the animation by pausing or sending an empty card as you wait to download the content)

Animation Blocking Computations Download times aside, the real performance advantage of display: none and opacity: 0 for cards that are swiped or are too far back in the list is that their content is already present in the DOM. (And as stated above, opacity: 0 has one further advantage: it does not trigger a reflow). By comparison physically adding and removing elements from the DOM requires an extra computation, namely inserting or removing the card node and all its children in the DOM tree. If this is done synchronously then you will have an animation blocking computation, whereby the swipe animation cannot take place until the DOM tree update is completed.

However let's keep things in perspective. Firstly, adding and removing nodes from the DOM tree is typically extremely fast. innerHTML has been demonstrated to be marginally faster at adding to the DOM but much slower at removing, so pick your poison with care. But unless you're adding tens or hundreds of kilobytes of data to your cards, the operation will likely take less than a millisecond. Secondly, you state that you will be retrieving content for the list from an API, which implies an asynchronous connection. If you take care when constructing your asynchronous functions, your function to add content to the DOM will not necessarily interfere with the animation. (Not to imply that JavaScript is multi-threaded; it is single threaded but well constructed asynchronous code means the order in which functions are executed does not matter). If the cards being added or removed are done so when an animation is not queued, any performance hit will become both shorter and less perceivable.

Finally, every DOM manipulation is a new render update so you want to do as few manipulations as possible. You would therefore create the elements against each other in memory and only at the very end insert the highest element into the DOM. See Fastest DOM insertion . If you can contain all card data within that card then each swipe would require just two DOM manipulations. It depends on what media the cards contain, but it's conceivable that, at worst, adding and removing cards to the stack will take only tens of milliseconds in combined time.

GPU Most rendering engines have access to a GPU which can achieve far better efficiency than the CPU in drawing and compositing operations that involve large numbers of pixels. Render layers are not rendered with the GPU by default. The page GPU Accelerated Compositing in Chrome states,

While in theory every single RenderLayer could paint itself into a separate backing surface [i.e. a GPU accessible compositing layer], in practice this could be quite wasteful in terms of memory (VRAM especially).

To ensure an animation such as opacity change is rendered using the GPU, you need to access the animation in such a way that it is implicitly composited. The above page has a comprehensive list of how to do this, but essentially you'd use CSS animations to change opacity which prompts the browser to promote the element to a compositing layer. The current code you have presented uses JavaScript to update opacity each animation frame, thus the opacity change is not a candidate for implicit compositing. (You appear to be using 3D transforms for the movement animation which triggers implicit compositing, so that is likely already GPU optimised). Changing the code to use CSS animations is not a trivial task, but it would very likely improve performance, specifically the frame rate during animation. Of course bench-marking is required to verify this for your specific scenario, see https://www.smashingmagazine.com/2016/12/gpu-animation-doing-it-right/ for a discussion on why some GPU animations may run slower.


In summary, the performance increase due to dynamically adding and removing elements from the virtual list, while potentially marginally higher than having the entire list fully loaded, is likely to be only a extra few milliseconds per swipe. With an asynchronous implementation, the frame rate during the animation should not change. This should normally be an easy concession for the likely large savings in initial download time, but must be considered in conjunction with other details of your particular implementation.

Read More

Friday, September 14, 2018

isDisplayed returns false for a visible element in Protractor

Leave a Comment

EDIT #4: Breakthrough!!

I started recursively going through the parent nodes and returning the same values as below. One of the parents--the inner mat-drawer-container--also returned false for isDisplayed (all the others returned true, which seems odd).

Looking at that node, it turns out that it's the only tag on the site to have the CSS of display: contents. Removing that causes the button in question--and everything else below it--to return true for isDisplayed. Heck, Protractor can even click the button and I can see the expected result in the browser.

Now I suppose the question remains: is this is expected behavior or a bug? It's not as straightforward as there being an ancestor with display: contents applied; I applied it directly to rb-container and Protractor was still able to find the button.


I'm working on end-to-end testing in Protractor for the first time, and I'm running into an issue when trying to test for a button being visible; despite the button element being in the DOM and visible, isDisplayed returns false and my assertion fails.

This is the initial assertion that's been failing:

expect(element(by.css("mat-drawer-content rb-container rb-fab-button[data-qaid='create-button'] > button")).isDisplayed()).toBe(true); 

(Yes, the selector is a mess, but I don't have control over the HTML.)

I've used a long browser.sleep() interval to essentially pause the browser in place so I could use the dev tools to inspect the humanly-visible element, and the CSS leads me to believe it should be detected as visible.

After searching for answers and/or bugs to no avail, I logged some information to the console which still leads me to believe that isDisplayed should return true:

[ EDITS #2, #3: Logged some more information on all the direct children of rb-container; only one node is "visible", according to Protractor. ]

  let selector = element.all(by.tagName("mat-drawer-content")).get(0).all(by.css("rb-container > *"));    selector.count().then(function(selCount) {      for (let match = 0; match < selCount; match ++) {        browser.sleep(1000).then(() => {         let elm = selector.get(match);          console.log("\n >> " + match + "]");          elm.getTagName().then(tag => { console.log("tag name:", tag); });         elm.getCssValue("visibility").then(vis => { console.log("visibility:", vis); });         elm.getCssValue("display").then(disp => { console.log("display:", disp); });         elm.getCssValue("opacity").then(opa => { console.log("opacity:", opa); });         elm.getCssValue("overflow").then(ov => { console.log("overflow:", ov); });         elm.getAttribute("hidden").then(hid => { console.log("hidden:", hid); });         elm.getAttribute("class").then(c => { console.log("class:", c)});         elm.getSize().then(size => { console.log("size:", size); });         elm.getCssValue("position").then(ov => { console.log("position:", ov); });         elm.getLocation().then(loc => { console.log("location:", loc); });         elm.isPresent().then(pres => { console.log("isPresent:", pres); });         elm.isDisplayed().then(disp => { console.log("isDisplayed:", disp); });       });      }    }); 

This is what I see logged:

 >> 0] tag name: div visibility: visible display: block opacity: 1 overflow: auto hidden: null class: title-tab dn db-m mediumGreyColor pl4 pv2 overflow-auto size: { ceil: {},   clone: {},   floor: {},   height: 62,   round: {},   scale: {},   toString: {},   width: 898 } position: static location: { ceil: {},   clone: {},   floor: {},   round: {},   scale: {},   toString: {},   translate: {},   x: 0,   y: 74.765625 } isPresent: true isDisplayed: false   >> 1] tag name: div visibility: visible display: block opacity: 1 overflow: auto hidden: null class: player-menu container overflow-auto dn db-m pv2 ng-star-inserted size: { ceil: {},   clone: {},   floor: {},   height: 64,   round: {},   scale: {},   toString: {},   width: 834 } position: static location: { ceil: {},   clone: {},   floor: {},   round: {},   scale: {},   toString: {},   translate: {},   x: 32,   y: 136.765625 } isPresent: true isDisplayed: false   >> 2] tag name: rb-fab-button visibility: visible display: block opacity: 1 overflow: visible hidden: null class: add-fab-button absolute dn db-m ng-star-inserted size: { ceil: {},   clone: {},   floor: {},   height: 56,   round: {},   scale: {},   toString: {},   width: 56 } position: absolute location: { ceil: {},   clone: {},   floor: {},   round: {},   scale: {},   toString: {},   translate: {},   x: 762,   y: 154.765625 } isPresent: true isDisplayed: false   >> 3] tag name: div visibility: visible display: block opacity: 1 overflow: visible hidden: null class: mr4-l w-100-m size: { ceil: {},   clone: {},   floor: {},   height: 0,   round: {},   scale: {},   toString: {},   width: 834 } position: static location: { ceil: {},   clone: {},   floor: {},   round: {},   scale: {},   toString: {},   translate: {},   x: 32,   y: 200.765625 } isPresent: true isDisplayed: false   >> 4] tag name: rb-table-wrapper visibility: visible display: block opacity: 1 overflow: visible hidden: null class: dn db-m size: { ceil: {},   clone: {},   floor: {},   height: 672,   round: {},   scale: {},   toString: {},   width: 834 } position: static location: { ceil: {},   clone: {},   floor: {},   round: {},   scale: {},   toString: {},   translate: {},   x: 32,   y: 200.765625 } isPresent: true isDisplayed: true   >> 5] tag name: div visibility: visible display: block opacity: 1 overflow: visible hidden: null class: container size: { ceil: {},   clone: {},   floor: {},   height: 0,   round: {},   scale: {},   toString: {},   width: 834 } position: static location: { ceil: {},   clone: {},   floor: {},   round: {},   scale: {},   toString: {},   translate: {},   x: 32,   y: 872.5625 } isPresent: true isDisplayed: false   >> 6] tag name: rb-table-wrapper visibility: visible display: none opacity: 1 overflow: visible hidden: null class: db dn-m size: { ceil: {},   clone: {},   floor: {},   height: 0,   round: {},   scale: {},   toString: {},   width: 0 } position: static location: { ceil: {},   clone: {},   floor: {},   round: {},   scale: {},   toString: {},   translate: {},   x: 0,   y: 0 } isPresent: true isDisplayed: false   >> 7] tag name: div visibility: visible display: none opacity: 1 overflow: auto hidden: null class: player-menu container overflow-auto db dn-m ng-star-inserted size: { ceil: {},   clone: {},   floor: {},   height: 0,   round: {},   scale: {},   toString: {},   width: 0 } position: static location: { ceil: {},   clone: {},   floor: {},   round: {},   scale: {},   toString: {},   translate: {},   x: 0,   y: 0 } isPresent: true isDisplayed: false 

With no hidden attribute set, a display value that isn't "none", visibility set to "visible", and non-zero size dimensions, I would expect isDisplayed to return true.

It's interesting to look at node 4, the only child element for which isDisplayed returns true, and compare it with node 2, the rb-fab-button element I'm trying to access. The only noticeable difference I can see is that rb-fab-button is positioned absolutely; however, the other statically-positioned elements also return false for isDisplayed.

Am I missing something? I'd settle for checking for css visibility, but my next test is to click that button, which errors if the element is not visible.

[ EDIT #1: Added some HTML: ]

<mat-drawer-container _ngcontent-c0="" class="root-container w-100 mat-drawer-container mat-drawer-container-explicit-backdrop" hasbackdrop="true" ng-reflect-has-backdrop="true">      <div class="mat-drawer-backdrop ng-star-inserted"></div>      <div tabindex="-1" class="cdk-visually-hidden cdk-focus-trap-anchor"></div>      <mat-drawer _ngcontent-c0="" class="mobile-drawer dn-m w-80 mat-drawer ng-tns-c2-0 ng-trigger ng-trigger-transform mat-drawer-over ng-star-inserted" tabindex="-1" ng-reflect-mode="over" style="box-shadow: none; visibility: hidden;">        <!-- [... mobile nav ...] -->      </mat-drawer>      <div tabindex="-1" class="cdk-visually-hidden cdk-focus-trap-anchor"></div>      <mat-drawer-content _ngcontent-c0="" class="mat-drawer-content">          <rb-navbar _ngcontent-c0="" _nghost-c7="" class="ng-star-inserted">            <!-- [... nav bar ...] -->          </rb-navbar>          <div _ngcontent-c0="" class="main-body">              <div _ngcontent-c0="" class="container h-100">                  <router-outlet _ngcontent-c0=""></router-outlet>                  <rb-system-setup _nghost-c18="" class="ng-star-inserted">                      <router-outlet _ngcontent-c18=""></router-outlet>                      <rb-site-tab class="ng-star-inserted">                          <mat-drawer-container autosize="" class="mat-drawer-container" ng-reflect-autosize="">                              <div class="mat-drawer-backdrop ng-star-inserted"></div>                              <div tabindex="-1" class="cdk-visually-hidden cdk-focus-trap-anchor"></div>                              <mat-drawer class="mat-drawer ng-tns-c2-8 ng-trigger ng-trigger-transform mat-drawer-end mat-drawer-over ng-star-inserted" disableclose="true" mode="over" position="end" tabindex="-1" ng-reflect-position="end" ng-reflect-mode="over" ng-reflect-disable-close="true" style="box-shadow: none; visibility: hidden;">                                  <rb-create-site _nghost-c20="" ng-reflect-side-panel="[object Object]" ng-reflect-side-panel-container="[object Object]" ng-reflect-ng-grid="[object Object]" ng-reflect-is-editing="false" ng-reflect-timezones="[object Object],[object Object">                                      <rb-side-panel _ngcontent-c20="" _nghost-c24="" ng-reflect-title="Add Site" ng-reflect-close-button-label="Cancel" ng-reflect-submit-button-label="CREATE_SITE.SUBMIT" ng-reflect-show-submit-button="true" ng-reflect-modal-submitting="true" ng-reflect-side-panel-container="[object Object]">                                        <!-- [... side panel ...] -->                                      </rb-side-panel>                                  </rb-create-site>                              </mat-drawer>                              <div tabindex="-1" class="cdk-visually-hidden cdk-focus-trap-anchor"></div>                              <mat-drawer-content cdkscrollable="" class="mat-drawer-content ng-star-inserted">                                  <div class="ph4-m h-100">                                      <rb-card _nghost-c21="">                                          <div _ngcontent-c21="" class="card rb-min-width-1 h-100">                                              <div _ngcontent-c21="" class="relative h-100">                                                  <rb-container _nghost-c22="" ng-reflect-row-data="[object Object]" ng-reflect-show-player="true" ng-reflect-show-search-bar="true" ng-reflect-include-edit="true" ng-reflect-include-delete="true" ng-reflect-include-stop="false" ng-reflect-include-sync="false" ng-reflect-include-checkbox="true" ng-reflect-include-fab-button="true" ng-reflect-route-type="systemSetup" ng-reflect-header="Sites" ng-reflect-mobile-table="site" ng-reflect-show-site-selector="false" ng-reflect-mobile-navigation="true">                                                      <div _ngcontent-c22="" class="title-tab dn db-m mediumGreyColor pl4 pv2 overflow-auto">                                                          <h1 _ngcontent-c22="" class="header-text pa2 fl ng-star-inserted">Sites</h1></div>                                                      <div _ngcontent-c22="" class="player-menu container overflow-auto dn db-m pv2 ng-star-inserted">                                                        <!-- [... player menu ...] -->                                                      </div>                                                      <rb-fab-button _ngcontent-c22="" class="add-fab-button absolute dn db-m ng-star-inserted" data-qaid="create-button" _nghost-c28="">                                                          <button _ngcontent-c28="" class="w-10 z-1 mat-fab mat-accent" mat-fab="" type="button" ng-reflect-disabled="false"><span class="mat-button-wrapper"><mat-icon _ngcontent-c28="" aria-label="add" class="mat-icon material-icons ng-star-inserted" role="img" aria-hidden="true">add</mat-icon></span>                                                              <div class="mat-button-ripple mat-ripple mat-button-ripple-round" matripple="" ng-reflect-centered="false" ng-reflect-disabled="false" ng-reflect-trigger="[object HTMLButtonElement]"></div>                                                              <div class="mat-button-focus-overlay"></div>                                                          </button>                                                      </rb-fab-button>                                                      <div _ngcontent-c22="" class="mr4-l w-100-m"></div>                                                      <rb-table-wrapper _ngcontent-c22="" class="dn db-m" ng-reflect-row-data="[object Object]" ng-reflect-enable-sorting="true" ng-reflect-include-checkbox="true" ng-reflect-is-clickable="false" ng-reflect-row-selection="multiple" ng-reflect-dom-layout="" ng-reflect-columns="[object Object],[object Object" ng-reflect-un-select-all_="[object Object]" ng-reflect-mobile-table="site" ng-reflect-mobile-navigation="true" ng-reflect-row-drag="false" ng-reflect-row-drag-field-name="">                                                          <ag-grid-angular class="ag-theme-material" ng-reflect-grid-options="[object Object]" ng-reflect-row-data="[object Object]" ng-reflect-column-defs="[object Object],[object Object" ng-reflect-default-col-def="[object Object]" ng-reflect-row-selection="multiple" ng-reflect-suppress-row-click-selection="true" ng-reflect-enable-sorting="true" ng-reflect-enable-filter="true" ng-reflect-suppress-no-rows-overlay="true" ng-reflect-dom-layout="" ng-reflect-row-drag-managed="false">                                                            <!-- [... data grid ...] -->                                                          </ag-grid-angular>                                                          <div class="backgroundColor w-100 fixed bottom-0 left-0 dn db-m ng-star-inserted">                                                              <div class="item-selection fr w-20">0/ 1 Selected</div>                                                          </div>                                                      </rb-table-wrapper>                                                      <div _ngcontent-c22="" class="player-menu container overflow-auto db dn-m ng-star-inserted"></div>                                                  </rb-container>                                              </div>                                          </div>                                      </rb-card>                                  </div>                              </mat-drawer-content>                          </mat-drawer-container>                      </rb-site-tab>                  </rb-system-setup>              </div>              <div _ngcontent-c0="" class="snacks fixed mw6 rb-min-width-2">                  <rb-global-snack-bar _ngcontent-c0="" _nghost-c8="" class="ng-tns-c8-3">                      <div _ngcontent-c8="" class="snackBar">                          <ul _ngcontent-c8="" class="ma0 pa0 list"></ul>                      </div>                  </rb-global-snack-bar>              </div>          </div>      </mat-drawer-content>  </mat-drawer-container>

0 Answers

Read More

Thursday, September 13, 2018

Strange bug with divs at same height overlapped with different z-index and with parent overflow hidden: border-bottom always is visible?

Leave a Comment

I created a speedometer that works very well and is to light (with CSS3,html and js code). But i noticed a strange bug with iphone....

This is the CODE:

$('#first').addClass('first-start');        //SECOND BAR  $('#second').addClass('second-start');    setTimeout(function() {    $('#second').addClass('second-pause');  }, 400);
#page {    margin-top: 50px;    width: 300px;    height: 300px;    background-color: #000;    border-radius: 8px;    display: flex;    align-items: center;    justify-content: center;    flex-direction: column;    z-index: 4;    overflow: hidden;  }    #box-first,  #box-second {    width: 200px;    height: 100px;    background-color: #fff;    border-radius: 200px 200px 0 0;    margin-top: 10px;    margin-bottom: 10px;    position: relative;    display: flex;    justify-content: flex-end;    align-items: flex-start;    z-index: 3;    overflow: hidden;  }    #first,  #second {    border-radius: 200px 200px 0 0;    margin: 0;    background: red;    width: 200px;    height: 100px;    transform: rotate(180deg);    -webkit-transform: rotate(180deg);    -moz-transform: rotate(180deg);    -ms-transform: rotate(180deg);    -o-transform: rotate(180deg);    transform-origin: 50% 100%;    -webkit-transform-origin: 50% 100%;    -moz-transform-origin: 50% 100%;    -ms-transform-origin: 50% 100%;    position: absolute;    top: 0px;    right: 0px;    border: 0;    z-index: 1;  }  #n1,  #n2 {    font-size: 20px;    color: #fff;    font-weight: bold;    position: absolute;    left: 50px;    right: 0;    text-align: center;    top: 50px;    bottom: 0;    display: flex;    align-items: flex-end;    justify-content: center;    width: 100px;    height: 50px;    background: #000;    border-radius: 100px 100px 0 0;    z-Index: 1;    overflow: hidden;  }  @keyframes first {    0% {      background-color: green;      transform: rotate(180deg);    }    33% {      background-color: yellow;      transform: rotate(240deg);    }    66% {      background-color: orange;      transform: rotate(300deg);    }    100% {      background-color: red;      transform: rotate(360deg);    }  }  @keyframes second {    0% {      background-color: green;      transform: rotate(180deg);    }    33% {      background-color: yellow;      transform: rotate(240deg);    }    66% {      background-color: orange;      transform: rotate(300deg);    }    100% {      background-color: red;      transform: rotate(360deg);    }  }  .first-start,  .second-start {    animation: first 2s linear forwards;  }  .first-pause,  .second-pause {    animation-play-state: paused;  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>  <div id="page">    <div id="box-first">      <div id="first"></div>      <div id="n1">1500</div>    </div>    <div id="box-second">      <div id="second"></div>      <div id="n2">270</div>    </div>  </div>

With iphone, so with safari, under (at the bottom side) div #n1 (the black div where there's number 1500) is visible a small white border or sometimes red (like #first). And this is impossible because the container has overflow: hidden, all divs have different z-Index and the absolute position of #n1 is correct.

How is possibile ?

Thanks and sorry for my english

This is the jsfiddle: This is jsfiddle: https://jsfiddle.net/k85t9zgq/33/

This is a bug's screenshot: enter image description here

2 Answers

Answers 1

I cannot test this, but I am pretty sure it's related to the fact that background use background-clip border-box by default and this is somehow a rendring issue. A potential fix is to make the background far from the border by adding a small padding and adjusting background-clip

$('#first').addClass('first-start');        //SECOND BAR  $('#second').addClass('second-start');    setTimeout(function() {    $('#second').addClass('second-pause');  }, 400);
#page {    margin-top: 50px;    width: 300px;    height: 300px;    background-color: #000;    border-radius: 8px;    display: flex;    align-items: center;    justify-content: center;    flex-direction: column;    z-index: 4;    overflow: hidden;  }    #box-first,  #box-second {    width: 200px;    height: 100px;    /* Changes*/    background: linear-gradient(#fff,#fff) content-box;    padding:1px;    box-sizing:border-box;    /**/    border-radius: 200px 200px 0 0;    margin-top: 10px;    margin-bottom: 10px;    position: relative;    display: flex;    justify-content: flex-end;    align-items: flex-start;    z-index: 3;    overflow: hidden;  }    #first,  #second {    border-radius: 200px 200px 0 0;    margin: 0;    background: red;    width: 200px;    height: 100px;    transform: rotate(180deg);    -webkit-transform: rotate(180deg);    -moz-transform: rotate(180deg);    -ms-transform: rotate(180deg);    -o-transform: rotate(180deg);    transform-origin: 50% 100%;    -webkit-transform-origin: 50% 100%;    -moz-transform-origin: 50% 100%;    -ms-transform-origin: 50% 100%;    position: absolute;    top: 0px;    right: 0px;    border: 0;    z-index: 1;  }  #n1,  #n2 {    font-size: 20px;    color: #fff;    font-weight: bold;    position: absolute;    left: 50px;    right: 0;    text-align: center;    top: 50px;    bottom: 0;    display: flex;    align-items: flex-end;    justify-content: center;    width: 100px;    height: 50px;    background: #000;    border-radius: 100px 100px 0 0;    z-Index: 1;    overflow: hidden;  }  @keyframes first {    0% {      background-color: green;      transform: rotate(180deg);    }    33% {      background-color: yellow;      transform: rotate(240deg);    }    66% {      background-color: orange;      transform: rotate(300deg);    }    100% {      background-color: red;      transform: rotate(360deg);    }  }  @keyframes second {    0% {      background-color: green;      transform: rotate(180deg);    }    33% {      background-color: yellow;      transform: rotate(240deg);    }    66% {      background-color: orange;      transform: rotate(300deg);    }    100% {      background-color: red;      transform: rotate(360deg);    }  }  .first-start,  .second-start {    animation: first 2s linear forwards;  }  .first-pause,  .second-pause {    animation-play-state: paused;  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>  <div id="page">    <div id="box-first">      <div id="first"></div>      <div id="n1">1500</div>    </div>    <div id="box-second">      <div id="second"></div>      <div id="n2">270</div>    </div>  </div>

Answers 2

I believe it's your border-radius property on #first and #second - Play around with the values on it and you will totally see what I mean.

Change this:

#first, #second {   border-radius: 200px 200px 0 0; /* ← CHANGE THIS */   margin: 0;   background: red;   width: 200px; /* ← CHANGE THIS TOO */   height: 100px;   transform: rotate(180deg);   transform-origin: 50% 100%;   position: absolute;   top: 0px;   right: 0px;   border: 0;   z-index: 1; } 

to:

#first, #second {   border-radius: 0; /* ← THIS IS WHAT YOU WANT */   margin: 0;   background: red;   width: 100%; /* ← THIS IS ALSO WHAT YOU WANT */   height: 100px;   transform: rotate(180deg);   transform-origin: 50% 100%;   position: absolute;   top: 0px;   right: 0px;   border: 0;   z-index: 1; } 

That faint white/gray line around your speedometer is no longer present.

Cheers and Happy coding :)

Read More

Friday, July 27, 2018

Set width/height of image to avoid reflow on image load

Leave a Comment

When I use image tags in html, I try to specify its width and height in the img tag, so that the browser will reserve the space for them even before the images are loaded, so when they finish loading, the page does not reflow (the elements do not move around). For example:

<img width="600" height="400" src="..."/> 

The problem is now I want to create a more "responsive" version, where for the "single column case" I'd like to do this:

<img style="max-width: 100%" src="..."/> 

but, if I mix this with explicitly specified width and height, like:

<img style="max-width: 100%" width="600" height="400" src="..."/> 

and the image is wider than the available space, then the image is resized ignoring the aspect ratio. I understand why this happens (because I "fixed" the height of the image), and I would like to fix this, but I have no idea how.

To summarize: I want to be able to specify max-width: 100%, and also somehow make sure the content is not reflowed when the images are loaded.

8 Answers

Answers 1

I'm also looking for the answer to this problem. With max-width, width= and height=, the browser has enough data that it should be able to leave the right amount of space for an image but it just doesn't seem to work that way.

I worked around this with a jQuery solution for now. It requires you to provide the width= and height= for your <img> tags.

CSS:

img { max-width: 100%; height: auto; } 

HTML:

<img src="image.png" width="400" height="300" /> 

jQuery:

$('img').each(function() {      var aspect_ratio = $(this).attr('height') / $(this).attr('width') * 100;     $(this).wrap('<div style="padding-bottom: ' + aspect_ratio + '%">'); }); 

This automatically applies the technique seen on: http://andmag.se/2012/10/responsive-images-how-to-prevent-reflow/

Answers 2

At first I would like to write about the answer from october 2013. This was incomplete copied and because of them it is not correct. Do not use it. Why? We can see it in this snippet (scroll the executed snippet to the bottom):

$('img').each(function() {       var aspect_ratio = $(this).attr('height') / $(this).attr('width') * 100;      $(this).wrap('<div style="padding-bottom: ' + aspect_ratio + '%">');  });
img { max-width: 100%; height: auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>  <div style="width:300px;border:1px solid red">  <img width="400" height="300" src="data:image/png;base64,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"/>  Some text  </div>

And we can see the text is afar from bottom. What is in this example incomplete/ incorrect? I will show it with correct example with pure JavaScript (we do not need to download jQuery for that).

Correct example with pure JavaScript

Please scroll the executed snippet to the bottom.

var imgs = document.querySelectorAll('img');  for(var i = 0; i < imgs.length; i++)  {      var aspectRatio = imgs[i].getAttribute('height') /                        imgs[i].getAttribute('width') * 100;        var div = document.createElement('div');      div.style.paddingBottom = aspectRatio + '%';      imgs[i].parentNode.insertBefore(div, imgs[i]);      div.appendChild(imgs[i]);  }
.restrict-container div{position:relative}  img  {      position:absolute;      max-width:100%;      top:0; left:0;      height:auto  }
<div class="restrict-container" style="width:300px;border:1px solid red">      <img width="400" height="300" src="data:image/png;base64,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"/>      Some text<br>      <img width="400" height="300" src="data:image/png;base64,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"/>      Some text  </div>

The mistake from answer from october 2013: the image should be placed absolute (position:absolute) to the wrapped container but it is not so placed.

This is the end of my answer to this question.


For further information read more about:

Answers 3

For a css only solution, you can wrap the img in a container where the padding-bottom percentage reserves space on the page until the image loads, preventing reflow.

Unfortunately, this approach does require you to include the image aspect ratio in your css (but no need for inline styles) by calculating (or letting css calculate for you) the padding-bottom percentage based on the image height and width.

If many of your images can be grouped into a few standard aspect ratios, then you could create a class for each aspect ratio to apply the appropriate padding-bottom percentage to all images with that aspect ratio. This may save you a little time and effort if you are not dealing with a wide variety of image aspect ratios.

Following is some example html and css for an image with a 2:1 aspect ratio:

HTML

<div class="container">   <img id="image" src="https://via.placeholder.com/300x150" /> </div> 

CSS

.container {   display: block;   position: relative;   padding-bottom: 50%; /* calc(100%/(300/150)); */   height: 0; }  .container img {   position: absolute;   top: 0;   left: 0;   width: 100%;   height: 100%; } 

The snippet below adds some extra html, css and javascript to create some visual top and bottom reference points and mimic a very slow loading image so you can visually see how the reflow is prevented with this approach.

const image = document.getElementById('image');  const source = 'https://via.placeholder.com/300x150';  const changeSource = () => image.src = source;    setTimeout(changeSource, 3000);
.container {    display: block;    position: relative;    padding-bottom: 50%; /* calc(100%/(300/150)); */    height: 0;  }    .container img {    position: absolute;    top: 0;    left: 0;    width: 100%;    height: 100%;  }    .top, .bottom {    background-color: green;    width: 100%;    height: 20px;  }
<div class="top"></div>  <div class="container">    <img id="image" src="" />  </div>  <div class="bottom"></div>

Answers 4

From this blog post by Jonathan Hollin: add the image's height and width as part of an inline style. This reserves space for the image, preventing reflow when the image loads, but it's also responsive.

HTML

<figure style="padding-bottom: calc((400/600)*100%)">   <img src="/images/kitten.jpg" /> </figure> 

CSS

figure {   position: relative; }  img {   max-width: 100%;   position: absolute; } 

The figure can be replaced with a div or any other container of your choice. This solution relies on CSS calc() which has pretty wide browser support.

Working Codepen can be seen here.

UPDATE:

I found a much cleverer alternate version of this: http://cssmojo.com/aspect-ratio-using-custom-properties-and-calc/. This still requires a wrapper element and it requires CSS custom properties, but I think it's much more elegant. Codepen example is here (credit to Chris Coyier's original).

Answers 5

I want to develop further my answer, and address the original question asked in May 31 '13 at 6:27 by gabor and it says:

Set width/height of image to avoid reflow on image load. I would like to fix this, but I have no idea how. To summarize: I want to be able to specify max-width: 100%, and also somehow make sure the content is not reflowed when the images are loaded.

Also I want to address de most recent request made by Ry- and it says:

This question has not received enough attention. Can this be done any better in 2018?

Now to make the answer even more clear the meaning of "somehow" acording with the Cambridge dictionary is as follows.

For English: someway in a way or by some means that is not known or not stated.

For American English: in a way which is not known or not stated.

Under this context I managed to somehow make it work using modern CSS and HTML5 Semantic Elements wich are considered some of the best Practices for 2018 acording to this article 30 Best HTML5 Practices 2018

Taking all of that in to consideration the resulting code shows the expected behaviour.

@charset "UTF-8";  :root{    --w:#fff;    --x:100%/600;    --bu:#e15f41;      --m:#786fa6;    --v:400;    --n:#f8a5c2;    --z:400/600;    --t:#333;    --r: calc(var(--z)*100%);    --b:#000;  }    body{    margin: 1rem;  	padding: 0;  	border: 0;    outline: 0;  	font-size: 100%;  	font: inherit;    color: var(--t);  	vertical-align: baseline;    box-sizing: border-box;    font-family: sans-serif;    background-color: var(--b);    min-width: 100px;    display: grid;  }  nav{    text-align: center;    background-color: var(--n);    padding: .3rem;  }  h1, h2, h3{    color: var(--w);  }  ul{    display: grid;    grid-template-columns: repeat(5, 1fr);    list-style: none;    padding: .2rem;  }  a{text-decoration: none; color: var(--b);}  a:hover{color:var(--w);text-shadow: 1px 1px 3px var(--t);}  main{    display: grid;    min-width: 100px;    background-color: var(--m);    padding: 1em;  }    figure{    --i:calc(var(--x)*var(--v));    margin: 0;    position: relative;        border: 4px solid white;    padding-top: var(--i);  }  img{    position: absolute;    top: 0px;    left: 0px;    max-width: 100%;    height: 100%;  }      @media only screen and (min-width: 600px){    main{      padding: 1.5em;      min-width: 100px;      background-color: var(--m);      display: grid;      grid-template-columns: repeat(2,1fr);      grid-gap: .5em;    }  }    @media only screen and (min-width: 1080px){    main{      padding: 2em;      min-width: 100px;      background-color: var(--m);      display: grid;      grid-template-columns: repeat(3,1fr);      grid-gap: .8em;    }  }
<!DOCTYPE html>  <html lang="en">  <head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <meta http-equiv="X-UA-Compatible" content="ie=edge">  <link rel="stylesheet" href="master.css">  <title>Document</title>  </head>  <body>    <header>          <nav>            <h1>site title</h1>            <ul class=''>              <li><a href="#">menu1</a></li>              <li><a href="#">menu2</a></li>              <li><a href="#">menu3</a></li>              <li><a href="#">menu4</a></li>              <li><a href="#">menu5</a></li>            </ul>          </nav>    </header>      <main>        <section>          <h3>Random Title</h3>          <figure>            <img class="on-off" src="" alt="image not found">          </figure>          <article><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></article>        </section>        <section>          <h3>Random Title</h3>          <figure>            <img class="on-off" src="" alt="image not found">          </figure>          <article><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></article>        </section>        <section>          <h3>Random Title</h3>          <figure>            <img class="on-off" src="" alt="image not found">          </figure>          <article><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></article>        </section>        <section>          <h3>Random Title</h3>          <figure>            <img class="on-off" src="" alt="image not found">          </figure>          <article><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></article>        </section>        <section>          <h3>Random Title</h3>          <figure>            <img class="on-off" src="" alt="image not found">          </figure>          <article><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></article>        </section>        <section>          <h3>Random Title</h3>          <figure>            <img class="on-off" src="" alt="image not found">          </figure>          <article><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></article>        </section>        <section>          <h3>Random Title</h3>          <figure>            <img class="on-off" src="" alt="image not found">          </figure>          <article><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></article>        </section>        <section>          <h3>Random Title</h3>          <figure>            <img class="on-off" src="" alt="image not found">          </figure>          <article><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></article>        </section>        <section>          <h3>Random Title</h3>          <figure>            <img class="on-off" src="" alt="image not found">          </figure>          <article><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></article>        </section>      </main>    <footer>              </footer>  </body>  </html>

Aditionally you can see how it works on codepen. GO TO CODEPEN

Answers 6

If I understand the requirements ok, you want to be able to set an image size, where this size is known only on content (HTML) generation, so it can be set as inline styles.

But this has to be independent of the CSS, and also prior to image loading, so also independent from this image sizes.

I have come to a solution tha involves wrapping the image in a div, and including in this div an svg that can be set to have proportions directly as an inline style.

Obviously this is not much semantic, but at least it works

The containing div has a class named img to show that it , well, should be an img

To try to reproduce the loading stage, the images have a broken src

.container {    margin: 10px;    border: solid 1px black;    width: 200px;    height: 400px;    position: relative;  }    .img {    border: solid 1px red;    width: fit-content;    max-width: 100%;    position: relative;  }    svg {    max-width: 100%;    background-color: lightgreen;    opacity: 0.1;  }    #ct2 {    width: 500px;  }    .img img {    position: absolute;    width: 100%;    height: 100%;    max-height: 100%;    max-width: 100%;    top: 0px;    left: 0px;    box-shadow: inset 0px 0px 10px blue;  }
<div class="container" id="ct1">      <div class="img">          <svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 400 300" width="400">          </svg>        <img width="400" height="300" src="missing.jpg">      </div>  </div>  <div class="container" id="ct2">      <div class="img">          <svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 40 30" width="400">          </svg>        <img width="400" height="300" src="missing.jpg">      </div>  </div>

Answers 7

<div style=" background-image:url('./media_assets/back1.gif'); background-size: cover; width: 100%; height: 500px; background-position: center; background-repeat: no-repeat;"> 

using image as a div background may solve your problem. this works well for responsive design

Answers 8

for responsive html wrap you image with a div fix only width of the div.

css

.imgPan{     width:200px;     } .imgPan img{     max-width:100%;     height:auto; } 

html

<div class="imgPan">    <img src="..."/> </div> 

now image will re-size in the aspect ratio.

Read More

Friday, July 13, 2018

Item Alignment in Navbar

Leave a Comment

I am utilizing w3schools' HTML5 and CSS to re-design our organization's public website. I currently have a logo in the center with I would like to have the bottom aligned with the bottom of the gray navbar. I also am having an issue displaying the font awesome 5 menu bars when the site is displayed in responsive mode (smaller than 1000px wide). I am not sure which CSS rules to apply to make this all work...

JSFiddle Initial

UPDATE 1

I was able to produce what I would like by adding a height to the col with the logos in it and setting positioning on the large logo. If there is a better way to do this please advise.

No, I just need help getting the bars to show up when the screen size is smaller than 1000px.

JSFiddle with Update 1

<!DOCTYPE html> <html> <title></title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Gugi|Lato|Raleway|Roboto|Roboto+Condensed"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css"> <style>     body {         /* font-family: 'Gugi', cursive; */         font-family: 'Roboto', sans-serif;         /* font-family: 'Roboto Condensed', sans-serif; */         /* font-family: 'Lato', sans-serif; */         /* font-family: 'Raleway', sans-serif; */         /* font-family: palatino, helvetica, sans-serif; */         /* font-family: "Segoe UI", Arial, sans-serif; */         background: #C6CCD0!important;     }      .w3-content {         max-width: 1200px;     }      #banner {         background-color: #022a3a;     }      ul.breadcrumb {         padding: 2.5px 4px;         list-style: none;         background-color: transparent;         display: inline-block;         line-height: 0.85;     }      ul.breadcrumb li {         display: inline;         font-size: 10px;     }      ul.breadcrumb li+li::before {         padding: 4px;         color: #fffef9;         /* content: "/\00a0"; */         content: ">";     }      ul.breadcrumb li a {         color: #fffef9;         text-decoration: none;     }      ul.breadcrumb li a:hover {         color: #e8b00f;         font-weight: 900;         text-decoration: underline;     }      ul.social {         padding: 5px 8px;         list-style: none;         background-color: transparent;     }      ul.social li {         color: #fffef9;         display: inline;         font-size: 16px;     }      ul.social li+li::before {         padding: 4px;         color: #fffef9;         /* content: "/\00a0"; */     }      ul.social li a {         color: #fffef9;         text-decoration: none;     }      ul.social li a:hover {         color: #e8b00f;         text-decoration: underline;     }      #logo {         float: left;         margin: 0 0 0 25px;     }      .gbl-logo {         display: inline-block;         height: 78px;         width: 180px;         outline: none;         background: transparent url("http://www.navy.mil/imgs/americas-navy-globe.png") no-repeat 0 0;         cursor: pointer;         /* text-indent: -9000px; */         text-indent: 100%;         white-space: nowrap;         overflow: hidden;     }      #___gcse_0 {         float: right;         width: 75%;     }      .gsc-control-cse {         /* font-family: Arial, sans-serif; */         border-color: #022a3a!important;         background-color: #022a3a!important;     }      .gsc-search-button-v2,     .gsc-search-button-v2:focus {         border-color: #C6CCD0!important;         background-color: #0076a9!important;         background-image: none;         filter: none;     }      .gsc-search-button-v2:hover {         border-color: #C6CCD0!important;         background-color: #e8b00f!important;         background-image: none;         filter: none;     }      #navbar {         height: 38.5px;     }      .loc-logo {         width: 100px;         /* height: 125px; */         /* position: absolute; */         /* bottom: 0; */         margin: 0 auto;         display: block;     } </style>  <body>     <!-- Start Banner and Navbar -->     <div class="w3-top">         <div id="banner" class="w3-hide-small w3-hide-medium">             <div class="w3-content">                 <div class="w3-row">                     <div class="w3-col m8 l9">                         <!-- Start Sit Collection Breadcrumbs -->                         <ul class="breadcrumb">                             <li><a href="#">Commander, Naval Surface Force, U.S. Pacific Fleet (COMNAVSURFPAC)</a></li>                             <li><a href="#">Commander, Naval Surface Group, Western Pacific (COMNAVSURFGRUWP)</a></li>                             <li><a href="#">Commander, Amphibious Squadron ELEVEN (COMPHIBRON 11)</a></li>                             <li><a href="#">USS Ashland (LSD 48)</a></li>                         </ul>                         <!-- End Sit Collection Breadcrumbs -->                     </div>                     <div class="w3-col m4 l3">                         <!-- Start Social Media Links -->                         <ul class="social">                             <li>Follow Us On:</li>                             <li><a href="#" title="Follow Us On Facebook"><i class="fab fa-facebook-square"></i></a></li>                             <li><a href="#" title="Follow Us On Twitter"><i class="fab fa-twitter-square"></i></a></li>                             <li><a href="#" title="Follow Us On Flickr"><i class="fab fa-flickr"></i></a></li>                             <li><a href="#" title="Follow Us On Wordpress"><i class="fab fa-wordpress"></i></a></li>                             <li><a href="#" title="Follow Us On Youtube"><i class="fab fa-youtube-square"></i></a></li>                         </ul>                         <!-- End Social Media Links -->                     </div>                 </div>                 <div class="w3-row">                     <!-- Start Site Logo -->                     <h1 id="logo">                         <a class="gbl-logo" href="#" title="Commander, Naval Surface Force, U.S. Pacific Home Page">                             <span>Commander, Naval Surface Force, U.S. Pacific Home Page</span>                         </a>                     </h1>                     <!-- Start Site Logo -->                 </div>             </div>         </div>         <div class="w3-content">             <div id="navbar" class="w3-bar">                 <div class="w3-row">                     <div class="w3-col l5">                         <!-- Start Global (Left) Navbar -->                         <div class="w3-left w3-hide-small w3-hide-medium">                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                         </div>                         <!-- End Global (Left) Navbar -->                     </div>                     <div class="w3-col l2 s3 m6">                         <a class="w3-hide-large w3-left" href="#home">                             <img style="width: 30px; margin: 0 10px; display: block;" src="https://www.public.navy.mil/surfor/crests/ashland_med.gif" />                         </a>                         <a class="w3-hide-small w3-hide-medium" href="#home">                             <img style="width: 100px; margin: 0 auto; display: block;" src="https://www.public.navy.mil/surfor/crests/ashland_med.gif" />                         </a>                     </div>                     <div class="w3-col l5">                         <!-- Start Local (Right) Navbar -->                         <div class="w3-right w3-hide-small w3-hide-medium">                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                             <a class="w3-bar-item w3-button" href="#about">ABOUT</a>                         </div>                         <!-- End Local (Right) Navbar -->                     </div>                     <div class="w3-col s1 m3">                         <!-- Hide Navbars and Display Menu Icon -->                         <a class="w3-bar-item w3-button w3-right w3-hide-large" href="javascript:void(0)" onclick="w3_open()">                             <i class="fa fa-bars"></i>                         </a>                     </div>                 </div>             </div>         </div>     </div> </body>  </html> 

2 Answers

Answers 1

Basically your fa bars icon is rendering properly, but it is pushed down to the next line, outside of the navbar bounds.

enter image description here


To fix this, I did a couple things. First I moved all the hide-medium, hide-small and hide-large classes up to the column level. This keeps the entire column from rendering even when the content inside them is hidden. Second I moved the large icon and small icon into their own columns (again, so now we can hide the entire column instead of just part of it). Then I adjusted the column size for the small icon. All this allowed the menu icon to be rendered inside the bounds of the navbar.

https://jsfiddle.net/vquagfh1/27/

enter image description here

<div id="navbar" class="w3-bar">     <div class="w3-row">       <div class="w3-col l5">         ...       </div>       <div class="w3-col l1 s1 m1 w3-hide-large" style="height: 38.5px;">         ...       </div>               <div class="w3-col l2 s3 m6 w3-hide-small w3-hide-medium" style="height: 38.5px;">         ...       </div>              <div class="w3-col s1 m1 w3-hide-large">         <!-- Hide Navbars and Display Menu Icon -->         <a class="w3-bar-item w3-button w3-right" href="javascript:void(0)" onclick="w3_open()">           <i class="fa fa-bars"></i>         </a>       </div>       <div class="w3-col l5 w3-hide-small w3-hide-medium">         ...       </div>     </div>   </div> 

Answers 2

Here is a very basic example using media queries, which as already mentioned, you should look into.

Fiddle: https://jsfiddle.net/ru1Lt8j3/1/

(Below is just for reference since you can't resize the SO embedded renderer)

.menu-item {    display: inline-block;    padding: 15px;  }  @media screen and (max-width: 500px) {    .logo {      float: left;      width: 16px;      height: 24px;    }    .somestuff {      display: none;    }  }
<div class="somestuff">this is some stuff</div>  <div class="menu">    <div class="menu-item">Link</div>    <div class="menu-item">Link</div>    <div class="menu-item">Link</div>    <img class="logo" src="http://via.placeholder.com/80x120">    <div class="menu-item">Link</div>    <div class="menu-item">Link</div>    <div class="menu-item">Link</div>  </div>

Read More

Thursday, July 12, 2018

SVG `<path>` javascript animation not working as expected

Leave a Comment

What I have achieved:

// Get the id of the <path> element and the length of <path>  var myline = document.getElementById("myline");  var length = myline.getTotalLength();  circle = document.getElementById("circle");  // The start position of the drawing  myline.style.strokeDasharray = length;    // Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw  myline.style.strokeDashoffset = length;    // Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolled  window.addEventListener("scroll", myFunction);    function myFunction() {    // What % down is it?    var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);    // Length to offset the dashes    var draw = length * scrollpercent;      // Reverse the drawing (when scrolling upwards)    myline.style.strokeDashoffset = length - draw;      //get point at length    endPoint = myline.getPointAtLength(draw);    circle.setAttribute("cx", endPoint.x);    circle.setAttribute("cy", endPoint.y);    }
body {    height: 2000px;    background: #f1f1f1;  }    #circle {    fill: red;  }    #mySVG {    position: absolute;    top: 15%;    width: 100%;    height: 1000px;      }    .st1 {    fill: none;    stroke-dashoffset: 3px;    stroke: grey;    stroke-width: 4;    stroke-miterlimit: 10;    stroke-dasharray: 20;  }  .st0 {    fill: none;    stroke-dashoffset: 3px;    stroke: red;    stroke-width: 5;    stroke-miterlimit: 10;    stroke-dasharray: 20;  }
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">    <path  class="st1" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.  </svg>    <svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">    <circle id="circle" cx="10" cy="10" r="10"/>    <path id="myline" class="st0" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.  </svg>

What I want is no matter which size or shape the SVG <path> is the growing line should be in the middle of the screen.

I tried changing the values of myline.style.strokeDashoffset = length //+newvalue - draw; and all but all it did was just ruins the consistency. so is there anyone who can help me solve this issue.?

Any help would be highly appreciatable.

4 Answers

Answers 1

(Update / New answer)

I think this is exactly what you want...

let roadmapSvg = document.getElementById("roadmap-svg");  let track = document.getElementById("track");  let body = document.getElementById("body");  let head = document.getElementById("head");    let totalLength = track.getTotalLength();  let trackPoints = [];  let getTrackBounds = () => track.getBoundingClientRect();  let scaleFactor;    body.style.strokeDasharray = totalLength;  body.style.strokeDashoffset = totalLength;    function setScaleFactor(){    scaleFactor = roadmapSvg.getBoundingClientRect().width / roadmapSvg.viewBox.baseVal.width;  }     setScaleFactor();    function setTrackPoints(){    let divisions = 1000;    let unitLength = totalLength / divisions;    trackPoints = [];    for(let i=0; i < divisions; i++){      let length = unitLength * i;      let {x,y} = track.getPointAtLength(length);      trackPoints.push({x: x*scaleFactor, y: y*scaleFactor, length});    }  }  setTrackPoints();      function draw(){    let currentLength = getCurrentLength();    body.style.strokeDashoffset = totalLength - currentLength;    headPos = track.getPointAtLength(currentLength);    head.setAttribute("cx", headPos.x);    head.setAttribute("cy", headPos.y);  }    function getCurrentLength(){    let centreY = window.innerHeight / 2;    let trackBounds = getTrackBounds();    let currentY = centreY - trackBounds.y;    if(currentY < 0) return 0;    if(currentY > trackBounds.height) return totalLength;        for(let point of trackPoints){      if(point.y >= currentY){        return point.length;      }    }        // (For safety) Sometimes none of the conditions match bcoz of low precision... Such situation only occurs a point very close to total length... Thus...    return totalLength;  }    document.addEventListener("scroll", draw);    window.addEventListener("resize", () => {    setScaleFactor();    setTrackPoints();    draw();  });
body {    background: #f1f1f1;    margin: 0;    padding: 0 20%;    font-family: sans-serif;  }    #roadmap-svg{    display: block;    max-width: 600px;    margin: 20px auto;    overflow: visible;  }    #roadmap-svg #head{    fill: red;  }    #roadmap-svg #track{    fill: none;    stroke-dashoffset: 3px;    stroke: grey;    stroke-width: 4;    stroke-miterlimit: 10;    stroke-dasharray: 20;  }  #roadmap-svg #body{    fill: none;    stroke-dashoffset: 3px;    stroke: red;    stroke-width: 5;    stroke-miterlimit: 10;    stroke-dasharray: 20;  }    .center-line{    position: fixed;    left: 0;    right: 0;    top: 50%;    border-top: 1px solid red;    background-color: rgba(255,255,255,0.9);  }
<div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempora in eaque rem eligendi corrupti voluptate, maxime cum cumque, eius delectus minus neque, dolorem optio cupiditate ratione! Excepturi fugit culpa quo?  Cum optio error ex voluptatem rerum eius sunt, nemo necessitatibus, exercitationem voluptatum illum, rem quibusdam accusamus deserunt sed. Iste odio obcaecati enim voluptate temporibus ab illo maxime et sit minima.  Odio ut dignissimos sed dicta recusandae esse, at molestiae quibusdam, consequatur aspernatur facilis, perferendis voluptatum adipisci. Dolores molestiae quos, doloribus excepturi officiis laborum ex officia reprehenderit esse perspiciatis alias itaque.  Delectus illum, asperiores at a ab quibusdam corporis necessitatibus. Libero eos vero blanditiis modi cum rem maxime delectus quisquam, facilis saepe sed eius corrupti nobis sunt, unde obcaecati commodi velit.  Saepe adipisci consectetur blanditiis quos enim praesentium, at magnam quibusdam nisi! Dolore, esse beatae! Enim, quam cum, qui voluptates fugiat, nihil mollitia possimus doloremque porro aspernatur nesciunt velit. Cum, adipisci?  Dolores doloribus nihil delectus consequuntur id assumenda tempora, illum, earum ab quasi quaerat sequi et hic veniam excepturi eligendi quod perspiciatis voluptatem ratione reprehenderit! Corrupti minima facilis soluta adipisci animi!  Iure, sed exercitationem. Quidem assumenda omnis dicta ducimus sunt, quibusdam excepturi molestias cumque! Illum ipsum perferendis dicta optio eum consequuntur soluta, corrupti nostrum est sed quaerat voluptates dolores perspiciatis? Ex!  Consequatur corporis ratione beatae. Magni amet doloribus deserunt, accusamus suscipit earum accusantium perferendis adipisci inventore, ab commodi odio necessitatibus aut omnis. Et quisquam esse deleniti, reprehenderit nihil optio aperiam fugit.  Aliquid error voluptatibus, quis quo eveniet nulla corrupti veniam culpa voluptas possimus tenetur nisi recusandae quae modi, animi dolores. Provident saepe nobis quos tenetur, veritatis laborum cupiditate molestias fugit consectetur.  A, perspiciatis illo sequi non eos facere temporibus dignissimos blanditiis ipsum harum eius culpa adipisci est ab nobis saepe mollitia quis laboriosam tenetur, repellat molestias. Quos ipsa magni dolores rerum.</div>  <svg id="roadmap-svg" viewBox="0 0 760 300">    <path  id="track" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" />    <path id="body" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" />    <circle id="head" cx="10" cy="10" r="10"/>  </svg>  <div class="center-line">Center Line</div>  <div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Sapiente officia saepe facilis? Cupiditate rem vel, quaerat ratione ipsam magnam fugiat praesentium incidunt! Eveniet cum officia impedit obcaecati id animi rerum?  Non beatae inventore quos optio temporibus ratione doloremque ullam animi dolore reiciendis sint, esse consequatur asperiores assumenda repudiandae obcaecati ab quas molestias harum eveniet amet natus ea? Ipsum, dolore suscipit.  Explicabo assumenda minus, reprehenderit modi, laboriosam placeat saepe at repudiandae perferendis fugit asperiores itaque. Vero fugiat voluptas asperiores dolores dolorum quis ipsa sapiente deleniti odio, deserunt, iure voluptates. Error, tempore.  Doloribus nesciunt praesentium ad aut minus aliquam aspernatur quas qui incidunt sunt, maxime tempora facilis, cum assumenda. Dolorum a tempore itaque impedit, ad, corporis tenetur enim nulla quas, harum fuga!  Quae repellat, obcaecati voluptate inventore quidem, labore quo corporis repudiandae, vel doloremque perferendis numquam aliquam nisi? Vel architecto ullam fugiat error corrupti? Cumque amet illo, possimus assumenda eos unde deleniti.  Enim tenetur possimus a neque, voluptatum reprehenderit, cum magni blanditiis quam atque dolorum veniam eveniet repellendus. Modi quibusdam maxime corrupti harum! Ullam vitae assumenda laboriosam nam officia eaque. Totam, dolorem.  Ad sapiente itaque blanditiis, sint iusto nemo laborum corrupti cupiditate obcaecati quam ipsa quis perferendis vitae enim atque ex a ratione. Doloribus aspernatur id ipsa recusandae labore aliquid, totam aperiam?  Recusandae delectus quidem, aspernatur nulla expedita accusantium quod praesentium inventore qui, pariatur ullam maxime! Numquam, sed sequi rem voluptates asperiores qui, culpa nesciunt magnam, quas doloribus praesentium et adipisci tempora.  Veniam, placeat vel nesciunt recusandae voluptates laboriosam totam doloremque saepe. Nam quo similique vero esse possimus architecto officiis harum ratione perspiciatis dolor ut, molestias odit consequatur quam asperiores? Id, quasi!  Ex expedita impedit aliquam et commodi voluptatibus, consequatur voluptate ea explicabo deserunt. Sapiente quo consequuntur enim dolores ea officia. Inventore ipsa dignissimos iste qui magnam reiciendis eveniet optio laudantium fugiat!</div>

Answers 2

I tried several ways to get point moving

  • inside the box
  • not sliding away until end
  • with minimal changes to original.

I made the following changes (working example below):

  • divider for percent I put 2000 (equal to 2000px, the containing body height)
  • I multiplied the scroll amount from top by 18 (suitable value was a compromise whether the top or bottom becomes behaving wierdly)
  • then finally I checked the percent value is not greater to one (it started to eat the 'worm' from the other end).

That's it! Maybe not the fanciest, but works.

Problematic here is the svg line is not linear from top to down, so direct element related values could not be chosen, or I at least did not find some. Thus, I ended up to simple solution and playing with parameters.

// Get the id of the <path> element and the length of <path>  var myline = document.getElementById("myline");  var length = myline.getTotalLength();  circle = document.getElementById("circle");  // The start position of the drawing  myline.style.strokeDasharray = length;    // Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw  myline.style.strokeDashoffset = length;    // Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolled  window.addEventListener("scroll", myFunction);    function myFunction() {    // What % down is it?    var scrollpercent = (document.documentElement.scrollTop * 18) / 2000;    if (scrollpercent > 1) scrollpercent = 1;    var draw = length * scrollpercent;      // Reverse the drawing (when scrolling upwards)    myline.style.strokeDashoffset = length - draw;      //get point at length    endPoint = myline.getPointAtLength(draw);    circle.setAttribute("cx", endPoint.x);    circle.setAttribute("cy", endPoint.y);  }
body {    height: 2000px;    background: #f1f1f1;  }    #circle {    fill: red;  }    #mySVG {    position: absolute;    top: 15%;    width: 100%;    height: 1000px;      }    .st1 {    fill: none;    stroke-dashoffset: 3px;    stroke: grey;    stroke-width: 4;    stroke-miterlimit: 10;    stroke-dasharray: 20;  }  .st0 {    fill: none;    stroke-dashoffset: 3px;    stroke: red;    stroke-width: 5;    stroke-miterlimit: 10;    stroke-dasharray: 20;  }
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">    <path  class="st1" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.  </svg>    <svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">    <circle id="circle" cx="10" cy="10" r="10"/>    <path id="myline" class="st0" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.  </svg>

Answers 3

As per the comments and few modification to css and svg code, i was able to get the line to the center of the page, please check the working example below:

// Get the id of the <path> element and the length of <path>  var myline = document.getElementById("myline");  var length = myline.getTotalLength();  circle = document.getElementById("circle");  // The start position of the drawing  myline.style.strokeDasharray = length;    // Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw  myline.style.strokeDashoffset = length;    // Find scroll percentage on scroll (using cross-browser properties), and offset dash same amount as percentage scrolled  window.addEventListener("scroll", myFunction);    function myFunction() {    // What % down is it?    var scrollpercent = (document.body.scrollTop + document.documentElement.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight);    // Length to offset the dashes    var draw = length * scrollpercent;      // Reverse the drawing (when scrolling upwards)    myline.style.strokeDashoffset = length - draw;      //get point at length    endPoint = myline.getPointAtLength(draw);    circle.setAttribute("cx", endPoint.x);    circle.setAttribute("cy", endPoint.y);  }
body {    margin: 0;    height: 1000px;    background: #f1f1f1;  }  #circle {    fill: red;  }  #mySVG {    top: 15%;    position: absolute;    width: 100%;  }  .st1 {    fill: none;    stroke-dashoffset: 1;    stroke: grey;    stroke-width: .5;    stroke-miterlimit: 1;    stroke-dasharray: 2;  }  .st0 {    fill: none;    stroke-dashoffset: 3px;    stroke: red;    stroke-width: 1;    stroke-miterlimit: 1;    stroke-dasharray: 2;  }  .grid {    position: fixed;    width: 1px;    height: 100%;    background: blue;    left: 50%;    top: 0;  }
<div class="grid"></div>  <svg id="mySVG" viewBox="0 0 200 72" preserveAspectRatio="xMidYMin slice">    <path class="st1" stroke-dasharray="10,9" d="m 0,5 0,4 c 0,3 2,6 5,6 l 108,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -25,0 c -3,0 -6,3 -6,6 0,3 3,6 6,6 l 35,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -18,0 c -3,0 -5,3 -5,6 l 0,4" />  </svg>    <svg id="mySVG" viewBox="0 0 200 72" preserveAspectRatio="xMidYMin slice">    <circle id="circle" cx="0" cy="3" r="2" />    <path id="myline" class="st0" stroke-dasharray="10,9" d="m 0,5 0,4 c 0,3 2,6 5,6 l 108,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -25,0 c -3,0 -6,3 -6,6 0,3 3,6 6,6 l 35,0 c 4,0 7,4 7,8 0,4 -3,7 -7,7 l -18,0 c -3,0 -5,3 -5,6 l 0,4" />  </svg>

Answers 4

I'd choose a different approach. I understand you want to find the point on the path that is closest to the middle of the screen. Let's do that:

  1. Find the coordinates of the middle of the screen and convert them to the coordinate system of the path. The SVG API has two functions for that: .getScreenCTM() and SVGPoint.matrixTransform().
  2. Find the point on the path (and its distance along the path) that is nearest to these coordinates. There is a bit of math and a search algorithm involved to do that. Mike Bostock has shown such an algorithm, and it's used here. Note that his function is open to a bit of tweaking (the precision parameter).
  3. Use these data to draw the circle and the dashoffset.

It is probably a good idea to refine this by introducing a throttle for the scroll events (second variant) and then set CSS transitions to avoid visible jumps.

Transitions for the circle positioning only work with a CSS transform property. (My solution does not neccessarily move the circle along the path while transitioning. It's possible to achieve that, but goes far beyond the scope of this answer.)

var mySVG = document.getElementById("mySVG");  // Get the id of the <path> element and the length of <path>  var myline = document.getElementById("myline");  var pathLength = myline.getTotalLength();  circle = document.getElementById("circle");  // The start position of the drawing  myline.style.strokeDasharray = pathLength;    // Hide the triangle by offsetting dash. Remove this line to show the triangle before scroll draw  myline.style.strokeDashoffset = pathLength;    // throttled scroll event listener  function throttle(ms, callback) {      var timer, lastCall=0;        return function() {          var now = new Date().getTime(),              diff = now - lastCall;          if (diff >= ms) {              lastCall = now;              callback();          }      };  }    window.addEventListener("scroll", throttle(100, myFunction));    // one initial execution  myFunction();    function myFunction() {    var center = mySVG.createSVGPoint();    // middle of browser viewport    center.x = window.innerWidth / 2;    center.y = window.innerHeight / 2;    // transform to path coordinate system    var matrix = myline.getScreenCTM().inverse();    center = center.matrixTransform(matrix);      //find nearest length on path    var draw = getNearestLength(center);      // Reverse the drawing (when scrolling upwards)    myline.style.strokeDashoffset = -draw - pathLength;      //get point at length    endPoint = myline.getPointAtLength(draw);    circle.style.transform = "translate(" + endPoint.x + "px, " + endPoint.y + "px)";  }    function getNearestLength(point) {    var precision = 8,        best,        bestLength,        bestDistance = Infinity;    // linear scan for coarse approximation    for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) {      if ((scanDistance = distance2(scan = myline.getPointAtLength(scanLength))) < bestDistance) {        best = scan, bestLength = scanLength, bestDistance = scanDistance;      }    }    // binary search for precise estimate    precision /= 2;    while (precision > 0.5) {      var before,          after,          beforeLength,          afterLength,          beforeDistance,          afterDistance;      if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = myline.getPointAtLength(beforeLength))) < bestDistance) {        best = before, bestLength = beforeLength, bestDistance = beforeDistance;      } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = myline.getPointAtLength(afterLength))) < bestDistance) {        best = after, bestLength = afterLength, bestDistance = afterDistance;      } else {        precision /= 2;      }    }    return bestLength;      function distance2(p) {      var dx = p.x - point.x,          dy = p.y - point.y;      return dx * dx + dy * dy;    }  }
body {    height: 2000px;    background: #f1f1f1;  }    #circle {    fill: red;  }    #mySVG {    position: absolute;    top: 15%;    width: 100%;    height: 1000px;      }    .st1 {    fill: none;    stroke-dashoffset: 3px;    stroke: grey;    stroke-width: 4;    stroke-miterlimit: 10;    stroke-dasharray: 20;  }  .st0 {    fill: none;    stroke-dashoffset: 3px;    stroke: red;    stroke-width: 5;    stroke-miterlimit: 10;    stroke-dasharray: 20;    transition: stroke-dashoffset 0.2s;  }    #circle {     transform: translate(10px, 10px);     transition: transform 0.2s;     }
<svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">    <path  class="st1" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.  </svg>    <svg id="mySVG" viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice" style="width: 6%; padding-bottom: 42%; height: 1px; overflow: visible">    <circle id="circle" cx="0" cy="0" r="10"/>    <path id="myline" class="st0" stroke-dasharray="10,9" d="M 20 0 v 20 a 30 30 0 0 0 30 30 h 600 a 40 40 0 0 1 0 80 h -140 a 30 30 0 0 0 0 60 h 200 a 40 40 0 0 1 0 80 h -100 a 30 30 0 0 0 -30 30 v 20" /> Sorry, your browser does not support inline SVG.  </svg>

Read More