Criando um Aplicativo de Clima em HTML, CSS e JavaScript

Criando um Aplicativo de Clima em HTML, CSS e JavaScript

Criar um aplicativo de clima é um projeto excelente para desenvolvedores web iniciantes. Ele ajuda a fortalecer suas habilidades fundamentais enquanto apresenta o uso prático de APIs em JavaScript. Você ganhará experiência prática em buscar e exibir dados de fontes externas. Essas habilidades são essenciais para desenvolver aplicativos do mundo real.

Neste tutorial, vou guiá-lo para criação de um aplicativo de clima bonito e interativo usando HTML, CSS e JavaScript . Este aplicativo permite que os usuários verifiquem o clima de qualquer cidade ou usem sua localização atual para obter a previsão do tempo. O aplicativo apresentará atualizações e previsões do tempo em tempo real por 24 horas.

Ao final deste tutorial, você terá um aplicativo de clima totalmente funcional que não só aprimora suas habilidades de codificação, mas também fornece uma ferramenta prática que você pode usar e exibir. Quer você esteja adicionando-o ao seu portfólio ou apenas experimentando novas técnicas, este projeto é um passo valioso em sua jornada de desenvolvimento web.

Tutorial em vídeo do aplicativo Weather em HTML e JavaScript

O vídeo do YouTube acima é um ótimo recurso se você prefere tutoriais em vídeo. Ele explica cada linha de código e fornece comentários, facilitando o acompanhamento do seu projeto de aplicativo de clima. Se você prefere ler ou precisa de um guia passo a passo, continue seguindo este post.

Etapas para construir um aplicativo de clima em HTML e JavaScript

Crie uma pasta com qualquer nome que desejar, por exemplo, weather-app.

Dentro dele, crie os arquivos necessários:  index.html,  style.css, e  script.js.

Baixe a pasta Icons e coloque-a no diretório do seu projeto. Esta pasta contém ícones necessários para condições climáticas.

No seu  index.htmlarquivo, adicione a marcação HTML essencial para estruturar o layout do seu aplicativo Weather. Isso inclui uma entrada de pesquisa para nomes de cidades, um botão de localização e seções para exibir o clima atual e a previsão horária, tudo estruturado com tags semânticas.

<!DOCTYPE html>
<!-- Coding By CodingNepal - youtube.com/@codingnepal -->
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Weather App | CodingNepal</title>
  <!-- Linking Google fonts for icons -->
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0" />
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="container">
    <!-- Search section -->
    <div class="search-section">
      <div class="input-wrapper">
        <span class="material-symbols-rounded">search</span>
        <input type="search" placeholder="Enter a city name" class="search-input">
      </div>
      <button class="location-button">
        <span class="material-symbols-rounded">my_location</span>
      </button>
    </div>

    <!-- No results message -->
    <div class="no-results">
      <img src="icons/no-result.svg" alt="No results found" class="icon">
      <h3 class="title">Something went wrong!</h3>
      <p class="message">We're unable to retrieve the weather details. Enure you've entered a valid city or try again later.</p>
    </div>

    <!-- Container for displaying weather data -->
    <div class="weather-section">
      <div class="current-weather">
        <img src="icons/no-result.svg" class="weather-icon">
        <h2 class="temperature">00<span>°C</span></h2>
        <h5 class="description">Weather description</h5>
      </div>

      <!-- Hourly weather forecast list -->
      <div class="hourly-weather">
        <ul class="weather-list"></ul>
      </div>
    </div>
  </div>

  <script src="script.js"></script>
</body>
</html>

No seu  style.cssarquivo, adicione código CSS para estilizar seu aplicativo de clima e dê a ele um design responsivo e visualmente atraente. Brinque com cores, fontes e fundos diferentes para tornar a interface amigável e atraente.

/* Importing Google Fonts - Montserrat */
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Montserrat", sans-serif;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: #5f41e4;
}

.container {
  flex-grow: 1;
  overflow: hidden;
  max-width: 425px;
  border-radius: 10px;
  position: relative;
  background: #fff;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}

.search-section {
  display: flex;
  gap: 10px;
  padding: 25px;
  align-items: center;
}

.search-section .input-wrapper {
  height: 54px;
  width: 100%;
  position: relative;
}

.search-section .input-wrapper span {
  position: absolute;
  top: 50%;
  left: 17px;
  pointer-events: none;
  transform: translateY(-50%);
}

.search-section .search-input {
  height: 100%;
  width: 100%;
  outline: none;
  font-size: 1rem;
  font-weight: 500;
  border-radius: 6px;
  text-transform: uppercase;
  padding: 0 20px 0 50px;
  border: 1px solid #beb0ff;
  background: #fff;
  transition: 0.1s ease;
}

.search-section .search-input:focus {
  border-color: #5f41e4;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.14);
}

.search-section .search-input::placeholder {
  text-transform: none;
}

.search-section .location-button {
  height: 54px;
  width: 56px;
  cursor: pointer;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  background: #fff;
  color: #5f41e4;
  border: 1px solid #beb0ff;
  transition: 0.3s ease;
}

.search-section .location-button:hover {
  color: #fff;
  background: #5f41e4;
  border-color: #5f41e4;
}

.search-section .location-button span {
  font-size: 1.3rem;
}

.no-results {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 100%;
  display: none;
  padding: 40px;
  text-align: center;
  align-items: center;
  flex-direction: column;
  transform: translate(-50%, -50%);
  transition: 0.2s ease;
}

body.show-no-results .no-results {
  display: flex;
}

.no-results .title {
  font-weight: 700;
  margin: 25px 0 15px;
}

.no-results .message {
  font-weight: 500;
  line-height: 23px;
}

body.show-no-results .weather-section {
  visibility: hidden;
}

.weather-section .current-weather {
  display: flex;
  padding: 20px 0 50px;
  flex-direction: column;
  align-items: center;
}

.current-weather .weather-icon {
  width: 140px;
  aspect-ratio: 1;
}

.current-weather .temperature {
  font-size: 3.38rem;
  margin: 23px 0;
  display: flex;
}

.current-weather .temperature span {
  font-size: 1.56rem;
  font-weight: 500;
  margin: 5px 0 0 2px;
}

.current-weather .description {
  font-weight: 500;
  font-size: 1.25rem;
}

.hourly-weather {
  padding: 16px 25px;
  border-top: 1px solid #d5ccff;
}

.hourly-weather .weather-list {
  display: flex;
  gap: 41px;
  overflow-x: auto;
  padding-bottom: 16px;
  margin-bottom: -16px;
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
}

.hourly-weather:hover .weather-list {
  scrollbar-color: #bfbfbf transparent;
}

.hourly-weather .weather-list .weather-item {
  display: flex;
  gap: 7px;
  width: 60px;
  font-weight: 500;
  flex-direction: column;
  align-items: center;
}

.hourly-weather .weather-item .weather-icon {
  width: 28px;
  aspect-ratio: 1;
}

/* Responsive media query code for small screen */
@media (max-width: 624px) {
  body {
    padding: 15px;
  }

  .search-section {
    padding: 20px;
  }

  .no-results {
    padding: 30px;
  }

  .hourly-weather {
    padding: 16px 20px;
  }

  .hourly-weather .weather-list {
    gap: 32px;
  }
}

No seu script.jsarquivo, adicione código JavaScript para tornar seu aplicativo de clima interativo e funcional. Este código buscará o clima atual e a previsão horária de uma API externa e, em seguida, atualizará dinamicamente o DOM para exibir os dados em tempo real.

const searchInput = document.querySelector(".search-input");
const locationButton = document.querySelector(".location-button");
const currentWeatherDiv = document.querySelector(".current-weather");
const hourlyWeather = document.querySelector(".hourly-weather .weather-list");

const API_KEY = "YOUR-API-KEY-HERE"; // API key

// Weather codes for mapping to custom icons
const weatherCodes = {
  clear: [1000],
  clouds: [1003, 1006, 1009],
  mist: [1030, 1135, 1147],
  rain: [1063, 1150, 1153, 1168, 1171, 1180, 1183, 1198, 1201, 1240, 1243, 1246, 1273, 1276],
  moderate_heavy_rain: [1186, 1189, 1192, 1195, 1243, 1246],
  snow: [1066, 1069, 1072, 1114, 1117, 1204, 1207, 1210, 1213, 1216, 1219, 1222, 1225, 1237, 1249, 1252, 1255, 1258, 1261, 1264, 1279, 1282],
  thunder: [1087, 1279, 1282],
  thunder_rain: [1273, 1276],
}

// Display the hourly forecast for the next 24 hours
const displayHourlyForecast = (hourlyData) => {
  const currentHour = new Date().setMinutes(0, 0, 0);
  const next24Hours = currentHour + 24 * 60 * 60 * 1000;

  // Filter the hourly data to only include the next 24 hours
  const next24HoursData = hourlyData.filter(({ time }) => {
    const forecastTime = new Date(time).getTime();
    return forecastTime >= currentHour && forecastTime <= next24Hours;
  });

  // Generate HTML for each hourly forecast and display it
  hourlyWeather.innerHTML = next24HoursData.map((item) => {
    const temperature = Math.floor(item.temp_c);
    const time = item.time.split(' ')[1].substring(0, 5);
    const weatherIcon = Object.keys(weatherCodes).find(icon => weatherCodes[icon].includes(item.condition.code));

    return `<li class="weather-item">
            <p class="time">${time}</p>
            <img src="icons/${weatherIcon}.svg" class="weather-icon">
            <p class="temperature">${temperature}°</p>
          </li>`;
  }).join('');
};

// Fetch and display weather details
const getWeatherDetails = async (API_URL) => {
  window.innerWidth <= 768 && searchInput.blur();
  document.body.classList.remove("show-no-results");

  try {
    // Fetch weather data from the API and parse the response as JSON
    const response = await fetch(API_URL);
    const data = await response.json();

    // Extract current weather details
    const temperature = Math.floor(data.current.temp_c);
    const description = data.current.condition.text;
    const weatherIcon = Object.keys(weatherCodes).find(icon => weatherCodes[icon].includes(data.current.condition.code));

    // Update the current weather display
    currentWeatherDiv.querySelector(".weather-icon").src = `icons/${weatherIcon}.svg`;
    currentWeatherDiv.querySelector(".temperature").innerHTML = `${temperature}<span>°C</span>`;
    currentWeatherDiv.querySelector(".description").innerText = description;

    // Combine hourly data from today and tomorrow
    const combinedHourlyData = [...data.forecast?.forecastday[0]?.hour, ...data.forecast?.forecastday[1]?.hour];

    searchInput.value = data.location.name;
    displayHourlyForecast(combinedHourlyData);
  } catch (error) {
    document.body.classList.add("show-no-results");
  }
}

// Set up the weather request for a specific city
const setupWeatherRequest = (cityName) => {
  const API_URL = `https://api.weatherapi.com/v1/forecast.json?key=${API_KEY}&q=${cityName}&days=2`;
  getWeatherDetails(API_URL);
}

// Handle user input in the search box
searchInput.addEventListener("keyup", (e) => {
  const cityName = searchInput.value.trim();

  if (e.key == "Enter" && cityName) {
    setupWeatherRequest(cityName);
  }
});

// Get user's coordinates and fetch weather data for the current location
locationButton.addEventListener("click", () => {
  navigator.geolocation.getCurrentPosition(
    (position) => {
      const { latitude, longitude } = position.coords;
      const API_URL = `https://api.weatherapi.com/v1/forecast.json?key=${API_KEY}&q=${latitude},${longitude}&days=2`;
      getWeatherDetails(API_URL);
      window.innerWidth >= 768 && searchInput.focus();
    },
    () => {
      alert("Location access denied. Please enable permissions to use this feature.");
    }
  );
});

// Initial weather request for London as the default city
setupWeatherRequest("London");

Importante: Seu aplicativo de clima não funcionará até que você o conecte a uma API de clima. Inscreva-se para obter uma chave de API gratuita da WeatherAPI e adicione-a à API_KEYvariável em seu 
script.jsarquivo. Essa chave permite que seu aplicativo recupere previsões em tempo real e por hora. A chave será algo como isto: 5f2b6b5a24044bcdbbc103609241008 .

Depois que a chave API for adicionada ao código, o aplicativo de clima estará pronto para uso. Abra o index.htmlarquivo no seu navegador e insira o nome de uma cidade ou use sua localização para verificar o clima.

Conclusão

Concluindo, construir um aplicativo de clima com HTML, CSS e JavaScript é uma ótima maneira para iniciantes aprimorarem suas principais habilidades de desenvolvimento web e ganharem experiência valiosa com APIs. Ao seguir este guia, você criou um aplicativo de clima funcional e visualmente atraente que é um complemento perfeito para seu portfólio.

Para melhorar ainda mais suas habilidades, você pode conferir outros projetos JavaScript relacionados, como Formulário de login, Portfólio com React, Calculdora de Idade, Despertador e outros.

Cada um desses projetos foi criado para aprimorar sua compreensão de HTML e CSS, ao mesmo tempo em que oferece experiência prática com melhores técnicas de estilo e integrações de API.

Se você encontrar algum problema ao criar seu aplicativo de clima, você pode baixar os arquivos de código-fonte para este projeto clicando no botão “Download”.

fullstack pro - Criando um Aplicativo de Clima em HTML, CSS e JavaScript

Sobre o Autor

Robson dos Santos
Robson dos Santos

DICA EXTRA!!!Algumas pessoas estão nos perguntando qual é o curso que recomendamos para quem deseja aprender programação, mesmo sem ter qualquer conhecimento sobre o assunto. Nossa recomendação, tanto para quem está iniciando, como para quem já possui mais experiência, é essa AQUI!

    0 Comentários

    Deixe um comentário

    O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *