<div>
<style>
.dim {
height:100%;
width:100%;
position:fixed;
left:0;
top:0;
z-index:1 !important;
background-color:black;
filter: alpha(opacity=75); /* internet explorer */
-khtml-opacity: 0.75; /* khtml, old safari */
-moz-opacity: 0.75; /* mozilla, netscape */
opacity: 0.75; /* fx, safari, opera */
}
.wrapper {
width: 100%;
top: 0px;
left: 0px;
position: absolute;
z-index: 5;
display: block;
}
.popup { width: 400px;
height: 200px;
margin: 0 auto;
padding: 40px;
background-color: #fff;
border: 1px solid #ccc;
color: #333;
}
</style>
<div class="dim"></div>
<div class="wrapper">
<div class="popup">
Subscribe box</div>
</div>
</div>
here's the code I actually got from another post and it makes the pop up for the most part and it dims the screen but it doesn't close or have a close button so there's no way of closing it once it's opened. so add a close button?
Your going to have to do a little JavaScript to get this to work, so that the code can detect the click event on the close button. I have previously used Colorbox to handle popups as it has quite a large number of features and is well documented, although you could also create your own using CSS3 and use javascript to add or remove a class.
Something like:
<style>
#basicElement {
/* style here */
}
#basicElement.open {
/* style here */
animation: popup 25s linear;
-moz-animation: popup 25s linear;
-ms-animation: popup 25s linear;
-o-animation: popup 25s linear;
-webkit-animation: popup 25s linear;
}
#basicElement.closed {
/* style here */
animation: popup 25s linear;
-moz-animation: popup 25s linear;
-ms-animation: popup 25s linear;
-o-animation: popup 25s linear;
-webkit-animation: popup 25s linear;
animation-direction: reverse;
-moz-direction: reverse;
-ms-direction: reverse;
-o-direction: reverse;
-webkit-direction: reverse;
}
#-webkit-keyframes popup {
0% {
background-size: 100% 100%;
}
100% {
background-size: 130% 130%;
background-position: center bottom;
}
}
</style>
<script>
$('#open').click(function (){ $(this).removeClass('closed').addClass('open'); });
$('#close').click(function (){ $(this).removeClass('open').addClass('closed'); });
</script>
Related
I'd like to achieve the following layout, in Ionic Vue, ideally using native components. Below is just a schema of what I want and I'm mostly interested in the desktop behavior:
Vue.createApp({
data: () => ({
isLeftOpen: false,
isRightOpen: false
}),
methods: {
toggleSidebar(side) {
this[`is${side}Open`] = !this[`is${side}Open`];
}
}
}).mount('#app')
body { margin: 0; overflow: hidden; }
* { box-sizing: border-box; }
#app {
height: 100vh;
background-color: #f5f5f5;
}
main {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
sidebar {
background-color: white;
display: block;
padding: 1rem;
width: 270px;
position: absolute;
top: 0;
bottom: 0;
transition: transform .21s cubic-bezier(.5,0,.3,1);
box-shadow: 0 1px 8px 0 rgb(0 0 0 / 20%), 0 3px 4px 0 rgb(0 0 0 / 14%), 0 3px 3px -2px rgb(0 0 0 / 12%);
}
sidebar[left] {
left: 0;
transform: translateX(-280px)
}
sidebar[right] {
right: 0;
transform: translateX(280px)
}
sidebar.open {
transform: translateX(0);
}
sidebar button {
width: 2rem;
height: 2rem;
position: absolute;
border-radius: 1rem;
border: 1px solid #f5f5f5;
right: .5rem;
top: .5rem;
cursor: pointer;
font-size: 1.5rem
display: flex;
align-items: center;
justify-content: center;
}
<script src="https://unpkg.com/vue#next/dist/vue.global.prod.js"></script>
<div id="app">
<main>
<button #click="toggleSidebar('Left')">left</button>
<button #click="toggleSidebar('Right')">right</button>
</main>
<sidebar left
:class="{open: isLeftOpen}">
Left sidebar
<button #click="toggleSidebar('Left')">×</button>
</sidebar>
<sidebar right
:class="{open: isRightOpen}">
Right sidebar
<button #click="toggleSidebar('Right')">×</button>
</sidebar>
</div>
In short, I want two sidebars completely unrelated, which should be opened/closed independently on all devices, according to user's choice. The argument that opening more than one sidebar at a time is not good UX doesn't really hold water on this project, as it's basically a full-screen map and the sidebars hold various controls and info about what's on the map. The requirement is that the user might want to have both sidebars open, but they might also want them both closed, even on big screens, to maximize the displayed portion of the map.
What options do I have here? To only have one "native" sidebar and mimic the second one with custom elements, using my own container and my own menu toggle resembling a native one? How would I make those look and behave as "native" on Android and iOS?
Here's my current layout, which achieves everything I want, except opening one sidebar always closes the other.
I don't know much about Ionic Vue (started using it today) but I'm decent in Vue. Tbh, I find Ionic Vue impressive. Very neat, documentation is stellar. But I'm stuck on this layout issue which seemed trivial at first.
Thanks for looking into this.
Hi I am a mobile app developer and not much familiar with web development, I was finding any approach to implement Progress Indicator before loading the flutter web app like Gmail loading screen. Flutter web is cool but it takes few moments before loading the app. Can we add any indicator for this loading duration? Any code implemented in flutter would be the part of flutter app and it won't work, There should be another approach to achieve this.
With the help of #Abhilash, I was able to accomplish this. I got loader code from w3schools.
My project/web/index.html is like this.
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script defer src="index.dart.js" type="application/javascript"></script>
<style>
.loading {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.loader {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid blue;
border-right: 16px solid green;
border-bottom: 16px solid red;
border-left: 16px solid pink;
width: 120px;
height: 120px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div class="loading">
<div class="loader"></div>
</div>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
In your question you mentioned
Any code implemented in flutter would be the part of flutter app and it won't work,...
I assume you tried to add the splash screen approach for android or IOS. Since flutter-web is simply an index.html and a couple of js files(for eg., main.dart.js), you should perhaps try the CSS loading animation trick. Since you didn't share any code I am not writing any code but the following would be my approach as explained by this red stapler video. He/she kindly provided a lot of CSS based animations here along with the codepen implementations for that.
So following would be my steps in the flutter_web_project\web\index.html file.
Add a span element in the body of index.html to show the css animation itself.
Create a div wrapper to position the span animation in your index.html.
Then listen to the onLoad event of the window and remove the div element from your page or fade it out as described in the video.
In addition to answer of #Shahzad Akram you should remove the loading div because in Safari browser it may cause of flickering. So in the first screen you need to implement the folowing code (for example, in initState method):
import 'package:universal_html/html.dart'
...
#override
void initState() {
super.initState()
// Remove `loading` div
final loader = document.getElementsByClassName('loading');
if(loader.isNotEmpty) {
loader.first.remove();
}
}
P.S. For nice loaders you can visit loading.io.
Adam's answer will remove loader before flutter is actually loaded.
I found this script to be the most complete answer:
<html>
<head>
<style>
.loading {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.loader {
border: 8px solid #f3f3f3;
border-radius: 50%;
border-top: 8px solid #00AD87;
border-right: 8px solid #C30E48;
border-bottom: 8px solid #00AD87;
border-left: 8px solid #C30E48;
width: 60px !important;
height: 60px !important;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<!-- First time loading -->
<div class="loading">
<div class="loader"></div>
</div>
<!-- Ensure first time loading progress is gone after app loads -->
<script>
window.addEventListener("flutter-first-frame", function() {
var element = document.getElementsByClassName("loading");
element[0].parentNode.removeChild(element[0]);
});
</script>
<script defer src="main.dart.js" type="application/javascript"</script>
</body>
</html>
If you want to remove loading div with just JS use this code
<script>
window.onload = (event) => {
console.log('page is fully loaded');
var element = document.getElementById("loader");
element.parentNode.removeChild(element);
};
</script>
Notice that it assumes that loader is a <div id="loader"></div> tag
In addition to answers from #Shahzad and #BambinoUA, I also needed to add defer keyword for main.dart.js script tag as well.
<script defer src="main.dart.js" type="application/javascript"></script>
Below is my scenario where this was needed:
app was hosted on Gitlab pages
browser was Chrome (with a slow internet)
In this case, only blank screen was visible until the whole script is downloaded. Then the animation was visible only for 0.5 second and flutter widgets loaded immediately after that. Thus failing the purpose of having loading animation. This doesn't happen in local testing.
I also tried putting the animation div before all scripts, but it didn't help.
I think the accepted answer is partially right as it's presented a loading indicator rather than a progress indicator. From flutter doc you can have a rough estimation of the flutter's actual loading progress. I've compiled an example using this indicator and it's showcased here.
Add this style
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
}
.progress-bar__container {
width: 80%;
height: 2rem;
border-radius: 2rem;
position: relative;
overflow: hidden;
transition: all 0.5s;
will-change: transform;
box-shadow: 0 0 5px #e76f51;
}
.progress-bar {
position: absolute;
height: 100%;
width: 100%;
content: "";
background-color: #e76f51;
top:0;
bottom: 0;
left: -100%;
border-radius: inherit;
display: flex;
justify-content: center;
align-items:center;
color: white;
font-family: sans-serif;
}
.progress-bar__text {
display: none;
}
and append this code on index.html of your flutter app.
function updateProgress(num) {
const progressBarContainer = document.querySelector('.progress-bar__container');
const progressBar = document.querySelector('.progress-bar');
const progressBarText = document.querySelector('.progress-bar__text');
let time = 0;
let endState = 100;
gsap.to(progressBar, {
x: num + "%",
duration: 2,
});
}
window.addEventListener('load', function(ev) {
var loading = document.querySelector('#loading');
loading.textContent = "Loading entrypoint...";
updateProgress(15);
_flutter.loader.loadEntrypoint({
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: async function(engineInitializer) {
loading.textContent = "Initializing engine...";
updateProgress(50);
let appRunner = await engineInitializer.initializeEngine();
updateProgress(80);
loading.textContent = "Running app...";
await appRunner.runApp();
updateProgress(100);
}
});
});
During startup of a flutter web app, we have the 2 phases: the first phase is when the index.html page has already loaded but the actually flutter app is loading. Then when the flutter app is loaded, we still might need to do some preparation within the flutter app. I like both phases to show an indication of loading and I want this to be the same. So... what I did:
First my index.html displays a gif which shows a circular progress indicator similar to the one I have in flutter (see 2) loading.gif
I do this similar to what this person describes: https://retroportalstudio.medium.com/indicate-website-loading-for-flutter-web-apps-7dc5e2c59e24
Then in my flutter app, I show this indicator:
return Container(
decoration: BoxDecoration(color: Colors.white),
child: Center(child: CircularProgressIndicator())
);
This indicator is pretty much the same as the gif. I created this gif with a combination of https://gifcap.dev/ and gimp to crop it.
The result is a fairly smooth loading circular progress indicator almost instant upon opening my website all the way up to when my flutterweb app opens.
Let me start by saying thank you in advance!
I'm on this site called StreamLabs for twitch streamers and they've introduced a way to use custom HTML, CSS, & JS to customize your look.
They have a thing called "Stream boss" that reacts to users following, sub, and/or donating.
I don't know how to change the name of the streamboss can someone help me with that
/*
bar(asset) width is 315
math for doing the stuff
x = {asset_length} - ( {asset_length} * ( {current_health}/{max_health} ) );
*/
// Events will be sent when the boss is damaged or killed.
// Please use event listeners to run functions.
document.addEventListener('bossLoad', function(obj) {
// obj.detail will contain information about the current boss
// this will fire only once when the widget loads
console.log(obj.detail);
//$('#user_pic').attr('src', obj.detail.boss_img);
$('#current_health').text(obj.detail.current_health);
$('#total_health').text(obj.detail.total_health);
$('#username').text(obj.detail.boss_name);
});
document.addEventListener('bossDamaged', function(obj) {
// obj.detail will contain information about the boss and a
// custom message
var x_coordinate = 0;
console.log(obj.detail);
// set the text
$('#current_health').text(obj.detail.boss.current_health);
// calculate where the x is
x_coordinate = 315 - (315 * (Number(obj.detail.boss.current_health) / Number(obj.detail.boss.total_health)));
// round the output
x_coordinate = -(~~x_coordinate);
// we animate the `background-position-x`
$('#vbi-health-bar').animate({
'background-position-x': x_coordinate + 'px'
}, 1000);
});
// Similarly for for when a boss is killed
document.addEventListener('bossKilled', function(obj) {
var x_coordinate = 0;
console.log(obj.detail);
$('#username').text(obj.detail.boss.boss_name);
//$('#user_pic').attr('src', obj.detail.boss.boss_img);
$('#current_health').text(obj.detail.boss.current_health);
$('#total_health').text(obj.detail.boss.total_health);
// calculate where the x is
x_coordinate = 315 - (315 * (Number(obj.detail.boss.current_health) / Number(obj.detail.boss.total_health)));
// round the output
x_coordinate = -(~~x_coordinate);
// we animate the `background-position-x`
$('#vbi-health-bar').animate({
'background-position-x': x_coordinate + 'px'
}, 1000);
});
#import url('https://fonts.googleapis.com/css?family=Teko:700');
/* All html objects will be wrapped in the #wrap div */
#username,
#user_hp_cont {
height: 33px;
line-height: 50px;
font-family: 'Teko', sans-serif;
font-size: 1.2em;
font-weight: 700;
text-shadow: 0px 0px 5.64px rgba(0, 0, 0, 0.004);
background-image: -webkit-linear-gradient(-180deg, #c0ff00 65%, #00ff0c);
/* For Chrome and Safari */
background-image: -moz-linear-gradient(-180deg, #c0ff00 65%, #00ff0c);
/* For old Fx (3.6 to 15) */
background-image: -ms-linear-gradient(-180deg, #c0ff00 65%, #00ff0c);
/* For pre-releases of IE 10*/
background-image: -o-linear-gradient(-180deg, #c0ff00 65%, #00ff0c);
/* For old Opera (11.1 to 12.0) */
background-image: linear-gradient(-180deg, #c0ff00 65%, #00ff0c);
/* Standard syntax; must be last #c0ff00, #00ff0c*/
color: transparent;
-webkit-background-clip: text;
background-clip: text;
text-transform: uppercase;
}
.boss_cont {
height: 120px;
color: white;
background-color: transparent;
background-image: url(https://s3.us-east-2.amazonaws.com/streamlabs-designers/indigo/1530912534steam_boss_frame.png);
background-size: auto 100%;
background-repeat: no-repeat;
background-position: center;
}
.vbi-aligner {
width: 370px;
height: 35px;
margin: 0 auto;
}
.vbi-aligner>#username {
float: left;
}
.vbi-aligner>#user_hp_cont {
float: right;
}
.vbi-health-frame {
position: absolute;
width: 315px;
height: 47px;
left: calc(50% - 157px);
background-image: url(https://s3.us-east-2.amazonaws.com/streamlabs-designers/indigo/1530912558health_bar_frame.png);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
-ms-transform: translateY(15px);
-webkit-transform: translateY(15px);
transform: translateY(15px);
overflow: hidden;
z-index: 1;
}
.vbi-health-magic {
background: transparent;
z-index: 0;
}
.vbi-health-bar {
position: absolute;
top: 1px;
width: 315px;
height: 45px;
background-image: url(https://s3.us-east-2.amazonaws.com/streamlabs-designers/indigo/1530912589health_bar.png);
background-repeat: no-repeat;
background-size: cover;
background-position: 0 0;
-ms-transform: translateX(0);
-webkit-transform: translateX(0);
transform: translateX(0);
-ms-transition: transform .5s ease-in-out;
-webkit-transition: transform .5s ease-in-out;
transition: transform .5s ease-in-out;
-webkit-clip-path: polygon(0 50%, 25px 0, 100% 0, 100% 100%, 25px 100%);
clip-path: polygon(0 50%, 25px 0, 100% 0, 100% 100%, 25px 100%);
}
<!-- All html objects will be wrapped in the #wrap div -->
<div class='boss_cont'>
<div class="vbi-aligner">
<div id='ussername'></div>
<div id='user_hp_cont'>
HP <span id='current_health'>0</span>/<span id='total_health'>0</span>
</div>
</div>
<div class="vbi-health-frame vbi-health-magic">
<div class="vbi-health-bar" id="vbi-health-bar"></div>
</div>
<div class="vbi-health-frame"></div>
<div style="display: none;" class='user_pic_cont'>
<img id='user_pic' src='' \>
</div>
<div id='message'></div>
</div>
It's right there in the custom JS section. Wherever you see the line:
$('#username').text(obj.detail.boss_name);
Change '#username' to whatever you want your boss name to be. It's in there twice.
i just hosted a small portfolio via github pages, and I tried to use media query to make it work on various device size.
The portfolio section includes these flipping card which i've been told are bogus on IOs devices when using chrome.
In fact it seems the back face are diplayed mirror on the Y axis.
I tried to debug by using CrossBrowser but without success.
Here's the repo with the code,
Here's a link to the bogus section.
Here some code should be enough to reproduce the issue (but i would still suggest to consider the repo code since i could miss something here)
html
<figure class="fig-container">
<div class="card">
<div img class="front face" style="background-image: url('http://img.youtube.com/vi/x10dBwZFi2Q/0.jpg');"></div>
<div class="back face">
<p><b>Location:</b> loc</p>
<p><b class="text-medium-big">Description: </b> desc</p>
</div>
</div>
</figure>
css
figure{
margin-bottom: 0px;
}
.fig-container {
max-width: 450px;
min-height: 160px;
/* horizontal center*/
margin-left: auto;
margin-right: auto;
}
.card {
box-sizing: border-box;
min-height: 250px;
transform-style: preserve-3d;
transition: all 0.5s linear;
border: 2px solid white;
border-radius: 20px;
}
.fig-container:hover .card {
transform: rotateY(180deg);
}
.face {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 17px;
}
.face.front {
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
.face.back {
display: block;
transform: rotateY(180deg);
box-sizing: border-box;
color: white;
font-size: 0.5em;
text-align: justify;
line-height: 1.5;
overflow-y: auto;
}
Anyone is able to see the bug and understand what it could be the problem?
My CSS is working perfectly fine on Google Chrome, Mozilla, and Opera. I have also tried Internet Explorer but that was a bust - Not that it matters.
My biggest issue right now is getting my CSS to work correctly on mobile safari (and other smartphone browsers like android).
HTML:
.load-more {
background-color: #00aa00;
color: #ffffff;
display: block;
font-family: 'Numans', sans-serif;
font-weight: lighter;
height: 3em;
line-height: 3em;
overflow: hidden;
padding: 0 3em;
text-align: center;
text-decoration: none;
transition: all .2s ease, background-color .01s ease, color .01s ease;
border-bottom: none;
}
.load-more.load-more--loading {
animation: rotate 1.5s linear infinite;
animation-delay: .2s;
background-color: transparent;
border: .3em solid #e1e1e1;
border-radius: 1.5em;
border-top-color: #00aa00;
box-sizing: border-box;
height: 3em;
color: transparent;
padding: 0;
pointer-events: none;
width: 3em;
-webkit-animation: rotation 2s infinite linear;
}
#-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(359deg);
}
}
<form action="stats.php" method="GET">
<div class="group">
<input type="text" name="player" autocomplete="off"><span class="highlight"></span><span class="bar"></span>
<label>USERNAME</label>
</div>
<center>
<input type="submit" value="CHECK STATS" class="load-more">
</a>
</center>
</form>
The CSS (and a javascript file that I'm using) turn the button into a loader when you click on it, but on mobile browsers like safari the button just disappears when you click it with no loader.
Example: https://epicmc.us
There's some support in iOS 7 and 8 for transform but none for animation in iOS. You're going to have to use jQuery or something to get the effect to work in mobile safari. Caniuse.com tells us the support here for these attributes: http://caniuse.com/#search=transform
This CSS works perfectly on mobile safari...
.load-more {
background-color: #00aa00;
color: #ffffff;
display: block;
font-family: 'Numans', sans-serif;
font-weight: lighter;
height: 3em;
line-height: 3em;
overflow: hidden;
padding: 0 3em;
text-align: center;
text-decoration: none;
border-bottom: none;
}
.load-more.load-more--loading {
background-color: transparent;
border: .3em solid #e1e1e1;
border-radius: 1.5em;
border-top-color: #00aa00;
box-sizing: border-box;
height: 3em;
color: transparent;
padding: 0;
pointer-events: none;
width: 3em;
-webkit-animation: rotation 2s infinite linear;
}
#-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(359deg);}
}