Preparing the DOM for a Single Page Application - javascript

What I am trying to achieve appears to be simple. I am assuming that all content visible on a page, is a child or grandchild of the tag of a HTML page? This text for example must be related to Body.
And this is a tree structure basically starting (visually) with Body.
I want to make a Single Page Application with JavaScript. But I need to prepare the DOM and here is where I struggle.
How do I set up the body of the page so that:
There is no scroll bars
The Body is always filling the entire content area of the browser (if it does not already)
Break out of CSS box model (appendChild 10 times stacks those elements, not flows them)
Any children Divs from Body, also by default break out of the CSS box model too.
I have searched for each step individually but I do not use JQuery, and to be honest, I would prefer to get rid of CSS too all but for the most basic of tasks. I would just like to have a known viewable region and be responsible for its positioning, sizing and content with JS.
Or. If you are similar with Flash. I want to treat the Body as my Stage and use it like a Display List with NO_SCALE enabled. Meaning that when you resize, that should "invalidate" the layout (that is upto me as the developer).
I am not the first person in the world to ask for this. So if you could even point me in the right direction, I would appreciate it.

Try CSS based solution to the fullest, then move on with Javascript. Following would give you pretty much what you want
There is no scroll bars
The Body is always filling the entire content area of the browser (if it does not already)
html, body {
margin : 0px
padding : 0px;
border : 0px;
overflow : hidden;
position : absolute;
left : 0px;
top : 0px;
}
Break out of CSS box model (appendChild 10 times stacks those elements, not flows them)
Any children Divs from Body, also by default break out of the CSS box model too.
put this first
* {
position : absolute;
}

Related

Display dynamic html content like an epub/ebook, without converting html to epub format?

I want to create a responsive, mobile optimized reading experience similar to an epub/ebook reader, like the Kindle app, or iBooks, using dynamic html as the source.
Imagine a long article or blog post that requires a lot of vertical scrolling to read, especially on a small mobile device. What I would like to do is break the long page into multiple full-screen sections, allowing the user to use left/right navigation arrows and/or the swipe gesture to "page" through the article.
There are many JS libraries available that can create a "slide show" or "carrousel" of pre-defined slides (using divs or other container elements). But I want the text and html content to dynamically re-flow to fit any device viewport and still be readable... just like an epub/ebook user interface, like the Kindle app or iBooks. So, for the same article, there would be many more "pages" on a phone than there would be on a tablet or desktop viewport, and those "pages" would need to be dynamically created/adjusted if/when the viewport size changes (like switching from portrait to landscape on a mobile device).
Here is an example of a javascript .epub reader: epub.js
... notice the responsive behavior. When you resize your viewport, all the text re-flows to fit the available space, increasing or decreasing the total number of "pages". The problem is that epub.js requires an .epub file as its source.
What I want is the same user interface and functionality for an html page.
I have searched and searched for some kind of library that can do this out of the box, but haven't been able to find anything.
I realize that I could use a conversion script to convert my html page into an .epub file, and then use epub.js to render that file within the browser, but that seems very round-about and clunky. It would be so much better to mimic or simulate the .epub reader user experience with html as the direct source, rendering/mimicking a client side responsive ebook user experience.
Does anyone know if something like this already exists, or how I could go about building it myself?
The crucial functionality is the dynamic/responsive text-reflow. When the viewport dimensions are reduced, the text/content needs to reflow to the next "page" to avoid any need for vertical scrolling. I don't know how to do this efficiently. If I were to code it myself, I might use something like the jQuery Columnize plugin, setting all columns to width: 100vw; height: 100vh, so that each column is like a "page", and then figuring out how to create a swipe UI between those "pages".
Any help is much appreciated!
This becomes very difficult if the html page is complex, eg with precisely positioned elements or images. However if (as in the epub.js example) the content consists only of headings and paragraphs, it is achievable.
The basic idea is to progressively add content until just before the page overflows. By keeping track of where we start and stop adding content, clicking to the next page is a case of changing the page start to the previous page end (or vice versa if you're going back).
Process for reshaping content into pages
Let's assume you have all your content in one long string. Begin by splitting all the content into an array of words and tags. It's not as easy as splitting by whitespace as whitespace between < and > should be ignored (you want to keep classnames etc within each tag). Also tags should be separated as well, even if there is no whitespace between the tag and a word.
Next you need a function that checks if an element's contents overflow the element. This question has a copy-paste solution.
You need two variables, pageStart and pageEnd, to keep track of what indexes in the array are the beginning and end of the current page.
Beginning at the index in pageStart you add elements from the array as content to the page, checking after each add whether or not the contents overflow. When they do overflow you take the index you're up to, minus 1, as the index for pageEnd.
Keeping tags across page breaks
Now if all's ticketyboo then this should fill the page pretty well. When you want to go to the next page set your new pageStart as pageEnd + 1 and repeat the process. However there are some issues that you may want to fix.
Firstly, what happens if the page overflows in the middle of a paragraph? Strictly speaking the closing tag, </p>, is not required in HTML, so we don't need to worry about it. But what about the start of the next page? It will be missing an opening tag and that is a major problem. So we have make sure we check if the page's content begins with a tag, and if it doesn't then we get the closest opening tag prior to the current pageStart (just step back along the array from pageStart) and add it in before the rest of the content.
Secondly, as shown in the example, if a paragraph continues onto the next page, the last line of the current page is still justified. You need to check if pageEnd is in the middle of a paragraph and if so add syle="text-align-last:justify;" to the opening tag of that paragraph.
Example implementation
A pen showing all this in action is at https://codepen.io/anon/pen/ZMJMZZ
The HTML page contains all content in one long element. The content is taken directly from the container #page and reformed into pages, depending on the size of #page. I have't implemented justifying the last line if a page break occurs within a paragraph. Resize the #page element in the css and see how the content resizes itself - note that since the page size is fixed you'll have to use click forward and back to trigger a recalculation. Once you bind the page size to the window size, recalculating pages on the fly simply involves adding a resize event listener to the window that calls fillPage.
No doubt there are numerous bugs, indeed it will sometimes display things incorrectly (eg skipping or repeating words at the beginning or end of a page), but this should give you an idea of where to start.
Take a look at this repository on GitHub. Otherwise, you can create a one-page website with many sections, each one as high as the viewport, by using only CSS (demo):
.section { height: 100vh; }
or by using JavaScript, adding an anchor to each section to navigate between them, and applying a responsive unit (my demo) for the text of each section, to adapt it on resize... Something like this:
var curr_el_index = 0;
var els_length = $(".container").length;
$(".next_section").on("click", function(e) {
curr_el_index++;
if (curr_el_index >= els_length) {
curr_el_index = 0;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
});
$(".previous_section").on("click", function(e) {
curr_el_index--;
if (curr_el_index < 0) {
curr_el_index = els_length - 1;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
});
* {
border: 0;
margin: 0;
padding: 0;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
body {
background-color: #1a1a1a;
}
section {
height: 100vh;
background-color: #eee;
border: 2px solid red;
font-size: 6vw;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="container">Section 1 Previous Next</section>
<section class="container">Section 2 Previous Next</section>
<section class="container">Section 3 Previous Next</section>
<section class="container">Section 4 Previous Next</section>
<section class="container">Section 5 Previous Next</section>
EDIT #1
An idea of algorithm, that come from a my codepen, that uses the same jQuery plugin:
Create your reader layout, copying the whole text in it
Use this jQuery plugin to check the text inside the viewport (demo)
Count the number of characters/WORDS with "Onscreen" label in the
viewport (a references)
Split the whole text in a list containing as many characters/WORDS as
there are in the "Onscreen" label
Create a section for each element of the obtained list, filling each
section with the relative text; the number of elements of the list
gives you the number of pages (sections) of the whole text. You may
navigate between sections like above
On resize event, redo [2-5] algorithm steps
Cheers
The idea is to have a div that will contain the whole text (let's call this div #epub_container). Then, you will have a div with the same size of the page viewport (let's call it #displayer) and it will contain #epub_container.
#displayer will have css overflow:hidden. So when the site loads, it will only show the first page, because the rest of the #epub_container will be hidden.
Then you need a page navigator to increment/decrement the page number. When the page number changes, we will move the top offset of the #epub_container based on that.
This is the jQuery function:
function move_to_page() {
var height = window.innerHeight;
var width = window.innerWidth;
var $displayer = $('#displayer');
var offset = $displayer.offset();
$displayer.height(height - offset.top - 5);
var $epub = $('#epub_container');
var offset_top = offset.top - $displayer.height() * m_page;
$epub.offset({top: offset_top, left: offset.left});
}
JSFiddle
EDIT: call move_to_page() after the text reflow in order to recompute the pages.
I created a plugin that handles this perfectly. It has features like dark mode, font changing, line height adjustment, select chapter in a side nav menu, save and restore scrolling/reading position. You can find it for free on git hub at https://github.com/E-TechDev/Html-Book-Reader
Screenshots
Light Mode Dark Mode Side Nav Menu Change Font Adjust Paragraph
You can try CSS scroll snap points on text with columns
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap_Points
Somehow make the columns as wide as the viewport, and allow horizontal snapped scrolling.
Update
I mean to try to do the text flowing entirely using css. Pen:
https://codepen.io/ericc3141/pen/RYZEpr
body {
scroll-snap-type: mandatory;
scroll-snap-points-x: repeat(100%);
}
#columns-test {
height: 80vh;
columns: 90vw auto;
}
All you need is to insert a page break at the right places when you load the page. You can take the cue from here:
Dynamic Page-Break - Jquery
Here you can set the page height to your viewport height. You can handle the rest with javascript and css.

Preventing divs from overlapping

I need help sizing the post-title div correctly at the following link. If you scale the result panel so that it is narrower, eventually the title will overlap the date. Rather than overlapping as shown here:
I would prefer that the title wrap onto a new line to avoid this collision. optimally, I would like it to also make use of the area above the the date like so:
Currently, the title will wrap once it reaches the end of the containing post div, as shown by the blue line beneath the title.
I have included a JSFiddle for you to test with.
http://jsfiddle.net/sph74/
You can use float: right on the date to get close to what you want. No more absolute positioning:
http://jsfiddle.net/sph74/1/
This is done via float: right (and that alone on the date). The .post-title element has to be display: inline or inline-block You could also use float: left, but that makes things a lot more hectic.
You also need to properly clear after the .post-heading element which I have done the old fashioned way via overflow: hidden.

A DIV's style width:"100%" seemingly causes a scroll bar due to lack of fix-width parent DIV

As asked and explained in this question, the problem with the DIV's width set to 100% is that it'll get the window's width and not the enclosed BODY element.
The solution suggested is to place an auxiliary DIV between BODY and the actual DIV and make its width fix. But that just puts the issue to the next level, doesn't it?
Since I don't know the screen size of my users' viewers (let's call it platform independence - a term I've heard somewhere is good to keep in mind when developing for the web, hehe), I need the main-all-mighty-rooted-and-parentest DIV to be filling out all available space without sticking out.
Of course, setting fix width on BODY won't work. Should I go ugly and pull the width of the part of the window that isn't the window, double it (once for each side) and retract that to set the fix width of some root DIV element?!
And if so - how?! I'm unclear on how to obtain the magic width (which, however, might be googleable) but mostly I'm unsure how to enter that parameter into the static CSS file. Will I have to do that dynamically using jQuery and ready function?
Edit
I executed this line from the console.
$("body")[0].outerHTML
The result was as follows - still displaying the scroll bar.
<body style="width: 600px;">
<div id="mapDiv" style="width: 100%; height: 100%; position: absolute;">!</div>
</body>
Then I executed this line.
$("#mapDiv")[0].style.position = ""
Poof, the scroll bar is gone. I thought absolute was the default setting... Apparently it isn't. There's the problem.
Based on your edit if you have that code then you are stretching your body tag to 600px and the <div> inside with absolute position and width 100%.
First the default for position is static.
Since you are using absolute position this happen, is taken off the DOM and search for a new containing block:
The containing block for a positioned box is established by the nearest positioned ancestor
If you don't set the body with any position value then the div is off and takes values in relation to another parent in this case is the window or <html> tag.
Then if you inspect the element is with the dimensions of html tag but positioned where he was in this example http://jsfiddle.net/wZ57C/. Is causing scroll because has 100% dimensions but positioned where body begins wich is at margin 8px aprox. Here you solve the scroll just adding position top:0 left:0 check here http://jsfiddle.net/wZ57C/1/.
But if you want the div be 100% of the body and position:absolute then make the body the relative parent http://jsfiddle.net/wZ57C/2/.

navigation 100% spread within a div with even padding

Hello!
I want to build a website navigation that is 100% spread within a tag and has even padding. The navigation items have no fixed number, they can be added dynamically. Or even not added, the site will be multilingual, so in different languages the size of the 'li' tags will differ.
I would like to know whether I can use js or jquery or any other method to calculate the sizes of all 'li' elements and give them a width (or padding) that will evenly spread my 'li' elements within the 'div'.
I looked for websites the like and found that cnn.com uses something like this but could not find what exactly.
Make all of your <li> tags inline-block and do text-align: justify on the parent, set to display: block and width: 100%. It should space them all out evenly and you can add whatever padding/margins you want.

Javascript DIV HTML display behind elements

I'm working with a embedded custom page used in a system the uses javascript to load html and display.
I have created a basic testing example to work out some bugs with two DIV elements. One is displayed with text and contains a mouse over and mouse out function call.
The functions are processed against the second div which should then be displayed to provide additional information.
When the second div is displayed though, it is being displayed behind the other elements in the page. I tried giving it a high z-index value thorough a css rule but it is still appearing behind other items.
Any suggestions appreciated.
Code:
So my CSS for the "hidden" div that i want to display onmouse...() is:
.description{ display:none; position:absolute; border:5px solid black; background-color: yellow; padding: 5px; z-index:10000;}
and my js. function is:
function ShowContent(d) { var dd = document.getElementById(d); dd.style.display = "block"; };
The vertical axis position of the element depends on several factors. One of them being the stack level value for a particular stack context (z-index)
To apply a z-index property your element must be positioned.
But its much more than that playing the game. Which are the display and position value of the surrounding elements, including the anestor of your div?
May be you are applying a z-index value to an element participating in other stacking context !
And their display value? Are you using the default block values or is there an inline level box ?
Are any floting element in the neighbourg ?
Show your HTML and css and I will give you a more precise answer.

Categories

Resources