Multiple Distinct Pages in One HTML File

Multiple distinct pages in one HTML file

Well, you could, but you probably just want to have two sets of content in the same page, and switch between them. Example:

<html>
<head>
<script>
function show(shown, hidden) {
document.getElementById(shown).style.display='block';
document.getElementById(hidden).style.display='none';
return false;
}
</script>
</head>
<body>

<div id="Page1">
Content of page 1
<a href="#" onclick="return show('Page2','Page1');">Show page 2</a>
</div>

<div id="Page2" style="display:none">
Content of page 2
<a href="#" onclick="return show('Page1','Page2');">Show page 1</a>
</div>

</body>
</html>

multiple pages in one html file without fixed nav on each page

I can't think of any pure CSS ways to do this, but it can easily be done with a little JavaScript to check if the hash is empty, and then show #home and hide it when there is a value.

window.onhashchange = checkHash;

checkHash();

function checkHash() {
var home = document.getElementById('home');

//Check if the hash is empty
if (window.location.hash.substring(1) == '') {
home.style.display = 'block';
} else {
home.style.display = 'none';
}
}
.section {
display: none;
}

.section:target {
display: block !important;
}
<div id="home" class="section">
<a href="#content">Content</a>
<a href="#somthingElse">Somthing Else</a>
<h3>Home</h3>
</div>
<div id="content" class="section">
<a href="#home">Home</a>
<h3>Content</h3>
</div>
<div id="somthingElse" class="section">
<a href="#home">Home</a>
<h3>Somthing Else</h3>
</div>

Multiple pages in one html page

You could play with the IDs only, but if you get many pages that starts to get a little tedious. I suggest using a class to do the hiding. Also, if you want there to be a common header for the pages, you just need to build it from HTML elements and then display the page links there and not within the page content.

I made an alternative suggestion where I added a 'page' class to all the page DIVs. Then what you can do is hide all the DIVs with the "page" class and show the one you want with an ID. This too is not a very flexible system, you can't easily do a dynamic amount of pages or a dynamic first page but it is a place to start. Here's my example:

This is in JSFiddle http://jsfiddle.net/H4dbJ/ but here's the code directly:

// show the given page, hide the rest
function show(elementID) {
// find the requested page and alert if it's not found
const ele = document.getElementById(elementID);
if (!ele) {
alert("no such element");
return;
}

// get all pages, loop through them and hide them
const pages = document.getElementsByClassName('page');
for (let i = 0; i < pages.length; i++) {
pages[i].style.display = 'none';
}

// then show the requested page
ele.style.display = 'block';
}
span {
text-decoration:underline;
color:blue;
cursor:pointer;
}
<p>
Show page
<span onclick="show('Page1');">1</span>,
<span onclick="show('Page2');">2</span>,
<span onclick="show('Page3');">3</span>.
</p>

<div id="Page1" class="page" style="">
Content of page 1
</div>
<div id="Page2" class="page" style="display:none">
Content of page 2
</div>
<div id="Page3" class="page" style="display:none">
Content of page 3
</div>

Hosting multiple pages using one HTML file

You can do this with HTML and CSS, with the :target selector. For example, in HTML:

<nav>
<ul>
<li><a href="#a">A</a></li>
<li><a href="#b">B</a></li>
<li><a href="#c">C</a></li>
</ul>
</nav>
<section id="a">
<h1>
Section A
</h1>
</section>
<section id="b">
<h1>
Section B
</h1>
</section>
<section id="c">
<h1>
Section C
</h1>
</section>

In your CSS:

section {
display: none;
}
section:target {
display: block;
}

You can test it on JSFiddle: http://jsfiddle.net/af180e3j/

Multiple html pages v/s Single html page

From easy to code perspective: (Not Recommended)

Obviously you can repeat the same HTML structure in all your pages and just change the center content in each page. Then you have to link your sub pages (1,2,3,4...) using normal anchor tags <a href="1.html"></a>.

Pros:

  1. Easy to create.
  2. Requires no / less technical expertise

Cons:

  1. Difficult to make changes to header and footer.

----------

From easy to maintenance perspective: (Good Option)

In case you want to have a common header and footer for all pages, then I would recommend creating a single page with following structure

Header
(1,2,3,4) <-Links
BODY CONTENT
FOOTER

Then on click of the links (1,2,3, etc.,) fetch the content from 1.html and inject it to the body of this index.html.

So as a result you are avoiding the need to repeat header and footer in multiple pages and you will adhere to DRY principle (DON'T REPEAT YOURSELF).

Pros:

  1. Elegant way to implement.
  2. Easy to make changes to the header/
    footer.

Cons:

Requires technical knowledge to use AJAX based content fetching and substitution in the parent page.

----------

From easy to maintain & manage content: (Best Option)

You can think about using CMS systems to maintain your simple website more efficiently.

Pros:

  1. Easy to Manage content
  2. Easy to make changes
  3. User friendly Rich text content editing features.
  4. Easy way to link all pages
  5. Easy to use Out of Box dynamic features (to generate your links 1, 2,3, etc.,)

Note: You would need a web server to host your website.

How to run a function on multiple HTML files and write the output of all executions into a single file

Since the pages you want to grab data from can be accessed over the internet, it would probably be easiest to achieve what you're looking for with a userscript. Since the URLs you need are already in an array, it's simply a matter of requesting each URL, parsing it, and adding the scraped information to your results array or object.

Here's an example, using the URLs of some random SO questions. Let's say I wanted to get the asker's name of each question. This is available via the selector string #question .user-details > a.

Put the URL you want the userscript to run on in the @match metadata section. Due to the same-origin policy, this needs to be on the same domain as the URLs in your array. Because the example URLs I'm using are on https://stackoverflow.com/, the @match also needs to be something on https://stackoverflow.com/.

Put the asynchronous code into an async IIFE so we can use await easily, and then for each URL, fetch it, transform the response text into a document so its elements can be easily querySelected, select the appropriate element, and push it to the results array. At the end, console.log the results:

// ==UserScript==
// @name scrape example
// @namespace CertainPerformance
// @version 1
// @match https://stackoverflow.com/questions/51868209/how-to-run-a-function-on-multiple-html-files-and-write-the-output-of-all-executi*
// @grant none
// ==/UserScript==

const urls = [
'https://stackoverflow.com/questions/313893/how-to-measure-time-taken-by-a-function-to-execute',
'https://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string',
'https://stackoverflow.com/questions/432174/how-to-store-arbitrary-data-for-some-html-tags',
];

(async () => {
const usernames = [];
for (const url of urls) {
const response = await fetch(url);
const responseText = await response.text();
const responseDocument = new DOMParser().parseFromString(responseText, 'text/html');
const username = responseDocument.querySelector('#question .user-details > a').textContent;
usernames.push(username);
}
console.log(usernames);
})();

To see this in action, install a userscript manager of your choice, such as Tampermonkey, install this script, navigate to the URL in the match metadata section (the URL of this page:

https://stackoverflow.com/questions/51868209/how-to-run-a-function-on-multiple-html-files-and-write-the-output-of-all-executi

), and open your console. The three usernames corresponding to those three question URLs should appear after a moment:

   ["Julius A", "Lightness Races in Orbit", "Community"]

If there are lots of links, you also might consider awaiting another Promise that resolves after, say, 5 seconds, on each iteration, to avoid hitting a server-side rate-limiter, eg

await new Promise(res => setTimeout(res, 1000));

If the amount of data you're scraping is significant, console.logging the results might not be easily accessible enough. One possible alternative is to put the stringified results into a new textarea, whose raw data can be more easily copied from:

const { body } = document;
const textarea = body.insertBefore(document.createElement('textarea'), body.children[0]);
textarea.value = JSON.stringify(usernames);

If the document is in an odd encoding, you may need to decode it before calling DOMParser, such as with TextDecoder. For example, for a page in windows-1255 encoding, you would await the arrayBuffer() called on the response and then decode it, like this:

for (const url of urls) {
const response = await fetch(url);
const responseBuffer = await response.arrayBuffer();
const responseDecoded = new TextDecoder('windows-1255').decode(responseBuffer)
const responseDocument = new DOMParser().parseFromString(responseDecoded, 'text/html');
const username = responseDocument.querySelector('#jobsArr_0').textContent;
usernames.push(username);
}

When used on the page you posted, this results in:

   ["אחמש"]

The #jobsArr_0 is just some element that contained Hebrew text - now, the characters aren't mangled anymore.

About implement single HTML page with multiple tabs via CSS with or without JavaScript aid

I do not recommend this for production and I would instead encourage you to use a proper tabs pattern so you can manipulate the relevant WAI-ARIA attributes or a SPA pattern (where you would manage focus after navigation occurs) etc.

But with that being said I did want to show that this is indeed possible (having initial content) using the :target selector, provided you don't mind having the DOM order be a little strange (which shouldn't have any accessibility issues as the other sections are hidden).

There is no actual need for the "Home" link I have added, I just put that there for completeness / to give you options.

Also notice something unusual - because of the page change in this manner there isn't always a <h1> - I am not actually sure (I will have to think) how to handle this best, but for now I have added a <h1> to each section so that every "page" has a <h1>.

ul {
list-style-type: none;
}

.page{
display: none;
}

.page:target {
display: initial;
}

.page:target ~ .initial {
display: none;
}
<nav>
<ul class="site-nav">
<li><a href="#home">home</a></li>
<li><a href="#one">page 1</a> </li>
<li><a href="#two">page 2</a> </li>
</ul>
</nav>
<main>
<section class="page" id="one" aria-labelledby="section1Heading">
<h1 id="section1Heading">Tab 1 content</h1>
</section>

<section class="page" id="two" aria-labelledby="section2Heading">
<h1 id="section2Heading">Tab 2 content</h1>
</section>

<section class="initial" id="home" aria-labelledby="homeHeading">
<h1 id="homeHeading">Initial Page Content / Home Page</h1>
</section>
</main>


Related Topics



Leave a reply



Submit