How to make a News Website with HTML, CSS, and JavaScript Integrated with NewsAPI

Feb. 20, 2024


2
9 min read
904

In today's digital age, staying updated with the latest news is easier than ever, thanks to the power of the internet. But have you ever wondered how websites dynamically fetch and display news articles from various sources? In this article, we'll delve into the intricacies of building a dynamic news website, using HTML, CSS, and JavaScript and employing the NewsAPI for fetching real-time news data.

Setting Up the HTML Structure:

Let's start by examining the HTML structure, the backbone of our news website:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Espere.in | News</title>
        <!-- Font Awesome -->
        <link
        href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
        rel="stylesheet"
        />
        <!-- Google Fonts -->
        <link
        href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
        rel="stylesheet"
        />
        <!-- MDB -->
        <link
        href="https://cdnjs.cloudflare.com/ajax/libs/mdb-ui-kit/6.2.0/mdb.min.css"
        rel="stylesheet"
        />
        <link rel="stylesheet" href="style.css">
</head>
<body>

<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-light bg-body-tertiary">
    <!-- Container wrapper -->
    <div class="container-fluid">
      <!-- Toggle button -->
      <button
        data-mdb-collapse-init
        class="navbar-toggler"
        type="button"
        data-mdb-target="#navbarSupportedContent"
        aria-controls="navbarSupportedContent"
        aria-expanded="false"
        aria-label="Toggle navigation"
      >
        <i class="fas fa-bars"></i>
      </button>
  
<!-- Collapsible wrapper -->
<div class="collapse navbar-collapse" id="navbarSupportedContent">
        <!-- Navbar brand -->
        <a class="navbar-brand mt-2 mt-lg-0" href="#">
          <img
            src="https://espere.in/static/images/newlogo.png"
            height="40"
            alt="MDB Logo"
            loading="lazy"
          />
        </a>
       <!-- Left links -->
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
    <li class="nav-item">
      <a class="nav-link" href="test.html">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link category-link" href="#" data-category="business">Business</a>
    </li>
    <li class="nav-item">
      <a class="nav-link category-link" href="#" data-category="technology">Technology</a>
    </li>
    <li class="nav-item">
      <a class="nav-link category-link" href="#" data-category="sports">Sports</a>
    </li>
  </ul>
  <!-- Left links -->
  
</div>
      <!-- Collapsible wrapper -->
  
      <!-- Right elements -->
      <div class="d-flex align-items-center">
        <form action="#">
            <div class="input-group">
                <input id="navbar-form" type="search" class="input form-control" aria-label="Search" placeholder="Search News">
                <div class="input-group-append">
                   <button type="submit" aria-label="Search" class="search_btn input-group-text border-0" id="search-addon">
                      <i class="fas fa-search"></i>
                   </button>
                </div>
             </div>
        </form>     
    </div>
    <!-- Right elements -->
    <!-- Container wrapper -->
  </nav>
  <!-- Navbar -->

<div class="container">
    <div class="gallery display_images row row-cols-1 row-cols-md-3 g-4 mb-4">
    </div>
    <button class="showmore"></button>
</div>
        
<script src="script.js"></script>
 <!-- MDB -->
 <script
 type="text/javascript"
 src="https://cdnjs.cloudflare.com/ajax/libs/mdb-ui-kit/6.2.0/mdb.min.js"
 ></script>
</body>
</html>

In this, we have used Bootstrap's CDN and we have created a navbar in which we have added some categories, you can add them as per your requirement. We've successfully incorporated our CSS and JavaScript files into the project, each playing a vital role in enhancing the website's aesthetics and functionality, as briefly outlined below.

  • Navbar: The navigation bar provides links for easy navigation to different sections of the website.
  • Container: This div element acts as a placeholder where news articles will be dynamically displayed.
  • CSS: Link tag include for loading CSS in our project /
  • JavaScript: Script tags include JavaScript code for fetching and displaying news articles.
  • External Libraries: External resources such as CSS frameworks (MDB) and Font Awesome icons are linked for styling and additional functionality.

Styling with CSS:

CSS plays a crucial role in enhancing the visual appeal and user experience of our news website. Let's explore how we style our components using CSS:

* Add this CSS to your stylesheet */
.hover-text {
  opacity: 0;
  transition: opacity 0.3s ease-in-out;
}

.card:hover .hover-text {
  opacity: 1;
}
/* Add this CSS to your stylesheet */
.image-container {
  position: relative;
  overflow: hidden;
}

.image-container img {
  width: 100%;
  height: auto;
  height: 250px;
  object-fit: cover;
}

.blur-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 8px 8px 0px 0px;
  backdrop-filter: blur(8px); /* Adjust the blur radius as needed */
  opacity: 0;
  transition: opacity 0.3s ease-in-out;
}

.card:hover .blur-overlay {
  opacity: 1;
}

.card:hover .interaction-buttons {
  opacity: 1;
  transform: translate(-50%, -50%);
}

.interaction-buttons {
  position: absolute;
  top: 20%;
  left: 35%;
  transform: translate(-50%, -50%);
  opacity: 0;
  transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
  cursor: default;
}

.touch-button,
.keyboard-button {
  padding: 10px 20px;
  margin: 5px;
  border-radius: 10px;
}
.none-touch-button,
.none-keyboard-button {
  padding: 10px 20px;
  margin: 5px;
  border-radius: 10px;
}
.touch-button{
    background-color: red;
    color: white;
    border: none;
}
.keyboard-button{
    background-color: white;
    color: red;
    border: none;
}

/* Add this CSS to your stylesheet */
.card:hover .keyboard-button {
  animation: animate__zoomInRight 0.9s;
}

@keyframes animate__zoomInRight {
  0% {
    opacity: 0;
    transform: translateX(50px) scale(0.8);
  }
  100% {
    opacity: 1;
    transform: translateX(0) scale(1);
  }
}
.card:hover .touch-button {
  animation: animate__zoomInRight 0.9s;
}

@keyframes animate__zoomInRight {
  0% {
    opacity: 0;
    transform: translateX(50px) scale(0.8);
  }
  100% {
    opacity: 1;
    transform: translateX(0) scale(1);
  }
}

By applying styles to elements such as the navbar, news cards, and interaction buttons, we ensure a visually appealing and cohesive design. Utilizing CSS frameworks like MDB UI Kit streamlines the styling process, ensuring compatibility and responsiveness across different devices.

  • Navbar: Styled to enhance visibility and user interaction.
  • Cards: News articles are presented in cards with hover effects for better user engagement.
  • Interaction Buttons: Buttons for actions like visiting the source website or viewing the publication date are styled for consistency and clarity.

Implementing JavaScript Functionality:

JavaScript breathes life into our news website, enabling dynamic interactions and data fetching. Here's how we implement JavaScript functionality:

const apikey = "d69fd79ca912474f974049523d33522d";
const input = document.querySelector("input");
const search_btn = document.querySelector(".search_btn");
const showmore_btn = document.querySelector(".showmore");

let page_num = 1;
let search_text = "";
let search = false;

input.addEventListener("input", (event) => {
    event.preventDefault();
    search_text = event.target.value;
});

search_btn.addEventListener("click", () => {
    if (input.value === "") {
        alert("Please enter some text");
        return;
    }
    cleargallery();
    search = true;
    SearchPhotos(search_text, page_num);
});

function cleargallery() {
    document.querySelector(".display_images").innerHTML = "";
    page_num = 1;
}
async function CuratedPhotos(page_num) {
    const data = await fetch(`https://newsapi.org/v2/top-headlines?country=in&page=${page_num}&pageSize=10&apiKey=d69fd79ca912474f974049523d33522d`, {
        method: "GET",
        headers: {
            Accept: "application/json",
            Authorization: apikey,
        },
    });
    const response = await data.json();
    console.log(response);

    display_images(response);
}

function display_images(response) {
    const container = document.getElementById("images-container"); // Assuming you have a container with id="images-container" where you want to display images
    response.articles.forEach((image) => {
        const photo = document.createElement("div");
        photo.classList.add("col"); // Adding column class
        
        // Check if image URL is available, if not, use default image
        const imageUrl = image.urlToImage ? image.urlToImage : 'https://images.pexels.com/photos/902194/pexels-photo-902194.jpeg';

        // Convert publishedAt date to a normal format
        const publishedDate = new Date(image.publishedAt);
        const formattedPublishedDate = publishedDate.toLocaleString('en-US', {
            year: 'numeric',
            month: 'long',
            day: 'numeric',
            hour: 'numeric',
            minute: 'numeric',
            second: 'numeric',
            timeZone: 'UTC' // Make sure to adjust time zone as per your requirement
        });

        photo.innerHTML = `
        <div class="col">
        <a target="_blank" href="${image.url}">
            <div class="card h-100">
                <div class="image-container">
                  <img src="${imageUrl}" class="card-img-top" alt="${image.author}" />
                  <div class="blur-overlay"></div>
                </div>
                <div class="card-body">
                  <h5 style="color: rgb(33, 33, 33); font-weight: bold;" class="card-title">${image.title}</h5>
                  <p class="card-text text-muted">${image.description}</p>
                </div>
                <div class="interaction-buttons">
                  <button class="touch-button"><i class="far fa-newspaper"></i> ${image.source.name}</button>
                  <button class="keyboard-button"><i class="far fa-calendar-days"></i> ${formattedPublishedDate}</button>
                </div>
                <div class="card-footer">
                  <small class="d-inline text-muted">Source: </small>
                  <small class="text-muted ms-1">${image.source.name}</small><br>
                  <small class="d-inline text-muted">Published: </small>
                  <small class="text-muted ms-1">${formattedPublishedDate}</small>
                </div>
              </div>
        </a>
    </div>
        `;
        
        document.querySelector(".display_images").appendChild(photo);
    });
}


const currentDate = new Date();

// Calculate the date one week ago
const oneWeekAgo = new Date();
oneWeekAgo.setDate(currentDate.getDate() - 7);

// Format dates as YYYY-MM-DD strings
const formattedCurrentDate = currentDate.toISOString().split('T')[0];
const formattedOneWeekAgo = oneWeekAgo.toISOString().split('T')[0];

async function SearchPhotos(query, page_num) {
    const data = await fetch(`https://newsapi.org/v2/everything?q=${query}&from=${formattedOneWeekAgo}&to=${formattedCurrentDate}&page=${page_num}&apiKey=d69fd79ca912474f974049523d33522d`, {
        method: "GET",
        headers: {
            Accept: "application/json",
            Authorization: apikey,
        },
    });
    const response = await data.json();
    console.log(response);

    display_images(response);
}

// Add an event listener to the window's scroll event
// Set the percentage to trigger loading more content (90% in this case)
const triggerPercentage = 80;

// Debounce function to limit the frequency of function calls
function debounce(func, wait) {
  let timeout;
  return function() {
    const context = this;
    const args = arguments;
    const later = function() {
      timeout = null;
      func.apply(context, args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}

// Debounced function to handle scroll events
const debouncedScroll = debounce(() => {
  // Calculate the percentage of scrolled distance
  const scrolledPercentage = (window.scrollY / (document.body.offsetHeight - window.innerHeight)) * 100;

  // Check if the user has scrolled to the specified percentage
  if (scrolledPercentage >= triggerPercentage) {
    // Load more photos or trigger the desired action
    loadMorePhotos();
  }
}, 100); // Adjust the debounce time as needed (200 milliseconds in this example)

// Attach the debounced scroll event listener
window.addEventListener("scroll", debouncedScroll);


function loadMorePhotos() {
    if (!search) {
        page_num++;
        CuratedPhotos(page_num);
    } else {
        if (search_text === "") return;
        page_num++;
        SearchPhotos(search_text, page_num);
    }
}
CuratedPhotos(page_num);

async function getCategoryNews(category, page_num) {
    const currentDate = new Date();
    const oneWeekAgo = new Date();
    oneWeekAgo.setDate(currentDate.getDate() - 7);

    const formattedCurrentDate = currentDate.toISOString().split('T')[0];
    const formattedOneWeekAgo = oneWeekAgo.toISOString().split('T')[0];

    const apiUrl = `https://newsapi.org/v2/everything?q=${category}&from=${formattedOneWeekAgo}&to=${formattedCurrentDate}&page=${page_num}&apiKey=d69fd79ca912474f974049523d33522d`;

    try {
        const response = await fetch(apiUrl);
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        const data = await response.json();
        display_images(data);
    } catch (error) {
        console.error('There was a problem fetching the news:', error);
    }
}


// Add event listeners to category links
const categoryLinks = document.querySelectorAll('.category-link');
categoryLinks.forEach(link => {
    link.addEventListener('click', function(event) {
        event.preventDefault();
        const category = this.dataset.category;
        cleargallery();
        search = true;
        search_text = category;
        getCategoryNews(category, page_num);
    });
});

JavaScript event listeners handle user interactions like clicking on category links or submitting search queries. Through asynchronous requests using async/await, we fetch news data from the NewsAPI, dynamically rendering it onto the webpage. The implementation of infinite scrolling ensures continuous loading of news articles as users scroll down the page, enhancing user experience.

  • Event Listeners: Respond to user actions such as clicking on category links or submitting search queries.
  • Data Fetching: Asynchronously fetch news data from the NewsAPI based on user input or category selection.
  • Infinite Scrolling: Implement a mechanism to load more articles dynamically as the user scrolls down the page.
  • API Integration: Fetch news articles from the NewsAPI using appropriate endpoints based on user input or category selection.
  • Display: Dynamically render fetched news articles onto the webpage for user consumption.

Conclusion:

Features like infinite scrolling enable users to navigate through a vast collection of news articles effortlessly. By optimizing website responsiveness and performance, we ensure a smooth and enjoyable browsing experience across various devices and screen sizes.

We have kept this article very simple, you just copy the code and create your project, if you face any issues then comment or message me directly.

In conclusion, building a dynamic news website requires a combination of HTML, CSS, JavaScript, and integration with external APIs like NewsAPI. Through meticulous design and implementation, we create a platform that empowers users with real-time access to news articles across different categories. Whether it's staying informed about global events or exploring niche topics of interest, a dynamic news website serves as an invaluable resource in today's fast-paced world.

css html Project APIs JavaScript Appreciate you stopping by my post! 😊

Comments


Profile Picture

Abdulla Fajal

You always post a nice article🤗🤗

Feb. 20, 2024, 2:05 p.m.

Profile Picture

Zehra Ahmad

Thank You so much Abdulla Fajal

Feb. 20, 2024, 2:08 p.m.

Add a comment


Note: If you use these tags, write your text inside the HTML tag.
Login Required