HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<div id="weather-widget" class="">
<video poster="//cit261.bermonpainter.com/rain.jpg" id="video" playsinline autoplay muted loop>
<source src="//cit261.bermonpainter.com/rain.webm" type="video/webm">
<source src="//cit261.bermonpainter.com/rain.mp4" type="video/mp4">
</video>
<main class="weather">
<article class="weather-now">
<ul>
<li class="weather-now-day"></li>
<li class="weather-now-date"></li>
<li class="weather-now-location"></li>
</ul>
<button class="weather-now-new-location" id="change-location-button">Change Location</button>
<ul>
<li class="weather-now-icon"> <span class="weather-description"></span></li>
<li class="weather-now-tempurature"></li>
</ul>
<dl class="weather-now-details">
<dt>Feels Like</dt>
<dd class="weather-now-precipitation"></dd>
</dl>
<dl class="weather-now-details">
<dt>Humidity</dt>
<dd class="weather-now-humidity"></dd>
</dl>
<dl class="weather-now-details">
<dt>Wind</dt>
<dd class="weather-now-wind"></dd>
</dl>
</article>
<aside class="weather-forecast">
<h2>Weather Forecast</h2>
</aside>
<footer>Bermon Painter | CIT261</footer>
</main>
<div id="mask-background"><button id="close-mask">Close</button></div>
<form id="change-location-form">
<label for="zip">Enter your postal code</label>
<input id="zipcode" type="number" name="zip" step="1" required />
<button type="submit" id="change-location-form-submit">Update Location</button>
</form>
</div>
@import url('https://fonts.googleapis.com/css?family=Montserrat:200,200i&display=swap');
// Root
html,body {
font: 100% Montserrat, Helvetica;
font-weight: 200;
height: 100%;
line-height: 1.5;
margin: 0;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
h2 {
font-weight: 200;
text-transform: uppercase;
}
sup {
font-weight: 200;
font-size: .5em;
margin-left: .1em;
position: relative;
top: -.75em;
}
input::-webkit-inner-spin-button,
input::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type="number"] {
-moz-appearance:textfield;
}
@keyframes blur {
to {
filter: blur(10px);
}
}
video {
// background: url('//cit261.bermonpainter.com/rain.jpg') no-repeat;
background-size: cover;
filter: grayscale(100%);
height: auto;
min-height: 100%;
position: fixed;
top: 50%;
left: 50%;
min-width: 100%;
transform: translateX(-50%) translateY(-50%);
transition: 1s opacity;
width: auto;
z-index: -100;
}
// Main wrapper
.weather {
background: rgb(2,0,36);
background: linear-gradient(-180deg, rgba(2,0,36,.6) 0%, rgba(9,9,121,.6) 35%, rgba(0,212,255,.6) 100%);
display: flex;
flex-direction: column;
height: 100%;
transition: filter 100ms ease-out 0ms;
width: 100%;
}
// Weather in the header
.weather-now {
color: #fff;
margin-bottom: 8%;
padding: 5%;
position: relative;
&-day {
font-size: 2em;
font-weight: bold;
text-transform: uppercase;
}
&-date, &-location {
font-size: .9em;
font-style: italic;
line-height: 1.2;
opacity: .5;
}
&-new-location {
background: transparent;
border: 2px solid rgba(#fff, .3);
border-radius: 3px;
color: #fff;
cursor: pointer;
font-size: .8em;
line-height: 1.5;
opacity: 1;
padding: 7px 14px;
pointer-events:auto;
position: absolute;
top: 10%;
right: 5%;
transition: background 350ms ease-out,
color 350ms ease-out,
opacity 350ms ease-out 400ms;
// transition-delay: 250s;
&:hover, &:focus {
background: rgb(183,218,244);
color: #100F26;
}
}
&-icon {}
&-tempurature {
font-size: 8em;
font-weight: bold;
margin-top: 70px;
}
&-details {
border-top: 1px solid rgba(255, 255, 255, .1);
display: flex;
flex-wrap: column;
margin: 0;
padding-top: 4%;
padding-bottom: 3%;
width: 100%;
&:last-of-type {
border-bottom: 1px solid rgba(255, 255, 255, .1);
}
dt {
text-transform: uppercase;
font-size: .8em;
font-weight: bold;
padding-left: 2%;
padding-top: .45%;
}
dd {
margin-left: auto;
}
}
}
// Upcoming weather
.weather-forecast {
background-color: rgba(#222831, .9);
color: #fff;
padding: 5%;
ul {
border-radius: 3px;
display: flex;
flex-direction: column;
}
&-item {
background-color: rgba(#fff, .04);
border-radius: 3px;
margin-bottom: 2px;
height: 70px;
padding: 5px 5px 5px 80px;
position: relative;
text-align: center;
transition: background-color 150ms, color 150ms, transform 150ms;
&:first-child {
margin-left: 0;
}
&:hover, &:focus {
background-color: #fff;
color: #222831;
transform: scale(1.07);
}
&-icon {
display: block;
height: 100px;
position: absolute;
top: -10px;
left: -10px;
width: 100px;
}
&-day, &-time {
float: right;
font-size: .8em;
margin-right: 6px;
margin-top: 40px;
}
&-tempurature {
font-size: 2.8em;
font-weight: bold;
float: left;
margin-top: 6px;
}
}
}
// Footer
footer {
background-color: rgba(#222831, .95);
color: rgba(#fff, .8);
font-size: .8em;
padding: 2em 0;
text-align: center;
text-transform: uppercase;
}
// Mask & change location form
#mask-background {
background: rgb(183,218,244);
border-radius: 3px;
color: rgb(183,218,244);
display: block;
font-size: .8em;
height: 30px;
width: 100px;
line-height: 1.5;
opacity: 0;
padding: 7px 14px;
pointer-events:none;
position: absolute;
top: 5%;
right: 5%;
transform: translate3d(0%, 0%, 0);
transition: top 450ms cubic-bezier(.55,0,.1,1),
right 450ms cubic-bezier(.55,0,.1,1),
height 450ms cubic-bezier(.55,0,.1,1),
width 450ms cubic-bezier(.55,0,.1,1),
background 450ms cubic-bezier(.55,0,.1,1),
border-radius 450ms cubic-bezier(.55,0,.1,1),
opacity 450ms cubic-bezier(.55,0,.1,1);
z-index: 1;
&:before {
content: "";
}
button {
background-color: transparent;
border: 0;
color: rgba(#fff, 0);
cursor: pointer;
height: 20px;
padding: 0;
pointer-events:auto;
text-indent: -9999px;
position: absolute;
top: 5%;
right: 5%;
transform: rotate(45deg);
width: 20px;
&:after, &:before {
background-color: #fff;
display: block;
content: '';
height: 2px;
position: absolute;
top: 9px;
left: 0;
width: 20px;
}
&:before {
height: 20px;
width: 2px;
top: 0;
left: 9px;
}
}
}
#change-location-form {
align-items: center;
display: flex;
flex-direction: column;
justify-content: center;
min-height: 100%;
opacity: 0;
pointer-events:none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
transition: opacity 150ms ease-out 50ms;
z-index: 100;
label {
color: #fff;
font-size: .8em;
opacity: .8;
padding-bottom: 5px;
pointer-events:auto;
text-align: left;
width: 220px;
}
input {
appearance: none;
background-color: rgba(#fff, 0);
border: 2px solid rgba(#fff, .5);
border-radius: 3px;
color: #fff;
font: 100% Montserrat, Helvetica;
font-weight: 200;
font-size: 2em;
font-weight: normal;
margin-bottom: 10px;
padding: 10px 15px;
pointer-events:auto;
transition: background-color 150ms ease-in;
width: 200px;
&:focus {
background-color: rgba(#fff, .1);
}
}
button {
background: rgb(25,116,181);
// background-size: 1px 500px;
border: 0px;
border-radius: 3px;
color: #fff;
cursor: pointer;
font-size: 1em;
line-height: 1.5;
padding: 20px 20px;
pointer-events:auto;
transition: background 250ms ease-out, color 250ms ease-out;
width: 235px;
&:hover, &:focus {
background: rgb(183,218,244);
color: #100F26;
}
}
}
// Modal is open
.has-modal {
.weather {
filter: blur(10px);
transition: filter 150ms ease-out 200ms;
// animation: blur 250ms linear forwards;
// animation-delay: 150ms;
pointer-events:none;
}
.weather-now-new-location {
opacity: 0;
transition-delay: 50ms;
// transition: opacity 350ms ease-out;
}
#mask-background {
background: rgb(2,0,36);
background: linear-gradient(-180deg, rgba(2,0,36,.5) 0%, rgba(9,9,121,.5) 35%, rgba(0,212,255,.55) 100%);
border-radius: 0;
display: block;
top: 0;
right: 0;
height: 100%;
opacity: 1;
pointer-events:none;
width: 100%;
&:before {
content: '';
}
}
#change-location-form {
opacity: 1;
transition: opacity 150ms ease-out 400ms;
}
}
var weatherModule = (function() {
// Set up settings for the API calls
let proxy = 'https://cors-anywhere.herokuapp.com',
currentWeatherAPIURL = 'https://api.openweathermap.org/data/2.5/weather',
forecastWeatherAPIURL = 'https://api.openweathermap.org/data/2.5/forecast',
iconURL = 'https://openweathermap.org/img/wn/',
weatherAPIKey = '9f72ffa9eabaa759e8b38618acb9acae';
// Cache HTML elements
let $widget = document.getElementById('weather-widget'),
$todaysDay = document.querySelector('.weather-now-day'),
$todaysDate = document.querySelector('.weather-now-date'),
$location = document.querySelector('.weather-now-location'),
$currentTempIcon = document.querySelector('.weather-now-icon'),
$currentTemp = document.querySelector('.weather-now-tempurature'),
$currentFeelsLike = document.querySelector('.weather-now-precipitation'),
$currentHumidity = document.querySelector('.weather-now-humidity'),
$currentWind = document.querySelector('.weather-now-wind'),
$forecastList = document.querySelector('.weather-forecast'),
$changeLocationButton = document.getElementById('change-location-button'),
$mask = document.getElementById('mask-background'),
$maskButton = document.getElementById('close-mask'),
$form = document.getElementById('change-location-form'),
$zipcode = document.getElementById('zipcode'),
$formSubmit = document.getElementById('form-submit');
// Set up placeholders for geolcation
let long,
lat;
// Convert a date value to day of the week
// Usage:
// convertToDay(value);
var convertToDay = function(day) {
// Create an array to contain the days of the week
let weekdays = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
// Convert the date into a date format
day = new Date(day);
// Return the day of the week
return weekdays[day.getDay()];
}
// Convert a date value to month of the year
// Usage:
// convertoMonth(value);
var convertToMonth = function(date) {
// Create an array to contain the months of the year
let months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
// Convert the date into a date format
date = new Date();
// Return the month of the year
return months[date.getDay()];
}
// Convert a date value to 12 hour AM/PM time format
// Usage:
// convertToTime(value);
var convertToTime = function(date) {
// Convert the date into a date format
date = new Date(date);
// Get the hours and minutes from the data value
let hours = date.getHours();
let minutes = date.getMinutes();
// Convert 24hrs to 12hrs /w AM or PM
let ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12; // convert '0' should to '12'
minutes = minutes < 10 ? '0'+minutes : minutes;
// Return the date in AM/PM time format
return `${hours}:${minutes} ${ampm}`;
}
// Get the date and format it into day of the week
// Set the HTML elements for the header of the page
var setDate = function(element, date) {
// Get the current date
let now = new Date();
// Set the HTML
$todaysDay.textContent = convertToDay(now);
$todaysDate.textContent = convertToMonth([now.getMonth()]) + " " + now.getDate() + ", " + now.getFullYear();
};
var fetchCurrentWeather = function(api) {
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
// Set response data to variables
const {name} = data
const {temp, temp_min, temp_max, pressure, humidity, feels_like} = data.main;
const {speed, deg} = data.wind;
// Add data to the interface
$location.textContent = name;
$currentTemp.innerHTML = `${Math.round(temp)}<sup>℉</sup>`;
$currentFeelsLike.innerHTML = `${Math.round(feels_like)}<sup>℉</sup>`;
$currentHumidity.textContent = `${humidity}%`;
$currentWind.textContent = `${speed} m/s`;
});
};
var fetchForecastWeather = function(api) {
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
// Set response data to variables
const {list} = data;
// If a forecast list already exists, remove it
let elementCheck = document.querySelector('.weather-forecast-list');
if(typeof(elementCheck) != 'undefined' && elementCheck != null){
elementCheck.remove();
}
// Create the forecast as an HTML list
// then append to the HTML
// <ul class="weather-forecast-list">
var forecastListParent = document.createElement('ul');
forecastListParent.setAttribute("class", "weather-forecast-list");
var listItem,
listItemIcon,
listItemDay,
listItemTime,
listItemTemp;
list.forEach(function(item) {
// <li class="weather-forecast-item">
// <span class="weather-forecast-item-icon">icon</span>
// <span class="weather-forecast-item-day">Monday</span>
// <span class="weather-forecast-item-time">7:00AM</span>
// <span class="weather-forecast-item-tempurature">23</span>
// </li>
listItem = document.createElement('li');
listItem.setAttribute("class", "weather-forecast-item");
// Add the icon
listItemIcon = document.createElement('img');
listItemIcon.setAttribute('class', 'weather-forecast-item-icon');
listItemIcon.src = `${iconURL}${item.weather[0].icon}@2x.png`;
listItem.appendChild(listItemIcon);
// Add the day
listItemDay = document.createElement('span');
listItemDay.setAttribute('class', 'weather-forecast-item-day');
listItemDay.innerHTML = convertToDay(item.dt_txt);
listItem.appendChild(listItemDay);
// Add the time
listItemTime = document.createElement('span');
listItemTime.setAttribute('class', 'weather-forecast-item-time');
listItemTime.innerHTML = convertToTime(item.dt_txt);
listItem.appendChild(listItemTime);
// console.log(item.dt_txt, convertToTime(item.dt_txt))
// Add the tempurature
listItemTemp = document.createElement('span');
listItemTemp.setAttribute('class', 'weather-forecast-item-tempurature');
listItemTemp.innerHTML = `${Math.round(item.main.temp)}<sup>℉</sup>`;
listItem.appendChild(listItemTemp);
// Append completed list /w data to the parent UL
// Count the loops and only render 5
forecastListParent.appendChild(listItem);
});
// Append complete forecast list ot the DOM
$forecastList.appendChild(forecastListParent);
});
};
// Get the geolocation information from the browser
// User lat/long for Charlotte is the user declines
// or geolocation is blocked
var getWeather = function() {
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(location => {
// Set the lat/long from the browser location
long = location.coords.longitude;
lat = location.coords.latitude;
// Set the API calls
const apiCurrentWeather = `${currentWeatherAPIURL}?lat=${lat}&lon=${long}&appid=${weatherAPIKey}&units=Imperial`,
apiForecastWeather = `${forecastWeatherAPIURL}?lat=${lat}&lon=${long}&cnt=10&appid=${weatherAPIKey}&units=Imperial`;
// AJAX request for current weather data
fetchCurrentWeather(apiCurrentWeather);
// API request for forecast weather data
fetchForecastWeather(apiForecastWeather);
});
} else {
// Set default lat/long to Charlotte
long = '-80.60368033352583';
lat = '35.01485103949014';
// Set the API calls
const apiCurrentWeather = `${currentWeatherAPIURL}?lat=${lat}&lon=${long}&appid=${weatherAPIKey}&units=Imperial`,
apiForecastWeather = `${forecastWeatherAPIURL}?lat=${lat}&lon=${long}&cnt=10&appid=${weatherAPIKey}&units=Imperial`;
// AJAX request for current weather data
fetchCurrentWeather(apiCurrentWeather);
// API request for forecast weather data
fetchForecastWeather(apiForecastWeather);
};
};
// Close the modal window
// Have to double up touch and click events
var closeModal = function() {
$maskButton.addEventListener("touchend", function(e){
e.preventDefault();
$widget.classList.toggle('has-modal');
});
$maskButton.addEventListener("click", function(e){
e.preventDefault();
$widget.classList.toggle('has-modal');
});
};
// Open the modal window
// Have to double up touch and click events
var changeLocation = function() {
$changeLocationButton.addEventListener("touchend", function(e){
$widget.classList.toggle('has-modal');
e.preventDefault();
});
$changeLocationButton.addEventListener("click", function(e){
$widget.classList.toggle('has-modal');
e.preventDefault();
});
// Get the zip code from the input on submit
$form.onsubmit = function(e) {
let zipcode = $zipcode.value;
// Set the API calls
const apiCurrentWeather = `${currentWeatherAPIURL}?zip=${zipcode}&appid=${weatherAPIKey}&units=Imperial`,
apiForecastWeather = `${forecastWeatherAPIURL}?zip=${zipcode}&cnt=10&appid=${weatherAPIKey}&units=Imperial`;
// AJAX request for current weather data
fetchCurrentWeather(apiCurrentWeather);
// API request for forecast weather data
fetchForecastWeather(apiForecastWeather);
// Prevent default for behavior
event.preventDefault();
// Close the modal
$widget.classList.toggle('has-modal');
};
};
return {
setDate: setDate(),
getWeather: getWeather(),
changeLocation: changeLocation(),
closeModal: closeModal()
};
})();
Also see: Tab Triggers