Here is my storyboard
I'm using autolayout, and NOT using size classes.
When I ran it on iPhone 5s, it works fine.(both portrait and landscape)
But when I ran it on iPhone 6 plus (portrait), it's not aligning properly.
on iPhone 6 plus (landscape), it's worse.
I know I can use -widgetMarginInsetsForProposedMarginInsets: to set the margin, but in that case I will need to customize the margin for every device. That would be horrible :(
So is there a way to align the subview to the title less painfully?
Setting the edge insets to zero should fix the problem:
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets
{
return UIEdgeInsetsZero;
}
Looks like you have to set it manually. You can do this by creating a constraint, then specifying an IBOutlet to it, and setting the constant depending on the device/orientation.
For reference, here are the margins I found you needed:
5S - 1 (2px)
6 - 1 (2px)
6 plus portrait - 5 (15px)
6 plus landscape - 34 (102px)
You can find which one you need from the size of the extension view, which is 414 pt for a portrait iPhone 6.
You need to customise the widget margins:
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets;
Documentation: https://developer.apple.com/library/ios/documentation/NotificationCenter/Reference/NCWidgetProviding_Protocol/index.html
Fixes for some devices. Requires Ericas UIDevice-Extension.
- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets
{
defaultMarginInsets.bottom = 0;
if ([UIDevice.currentDevice.modelIdentifier containsString:#"iPhone7,1"] && self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
defaultMarginInsets.left += 5;
} else if ([UIDevice.currentDevice.modelIdentifier containsString:#"iPhone7,1"] && self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) {
defaultMarginInsets.left += 34;
} else {
defaultMarginInsets.left += 1;
}
return defaultMarginInsets;
}
Related
I try to manage separators (like a "-") between each element of a list.
It's relatively simple when we only have one line, but I can't do it with more than one line.
When the site is displayed on a big screen I have:
Example center aligned
Listitem1 - listitem2 - listitem3 - ... - listitemX
The last item having no separator "-"
html
<p>
<a>listitem1</a>
<a>listitem2</a>
<a>listitem3</a>
<a>listitem4</a>
<a>listitem5</a>
<a>listitem6</a>
<a>listitem7</a>
...
<a>listitemX</a>
</p>
CSS
a:nth-child(n+2)::before {
content: " - "
}
This is relatively easy in CSS using :: before from the 2nd child...
But with media queries, when my screen shrinks and this same list spans multiple lines, I would like to remove the last "-" separator from each line.
Example center aligned
Listitem1 - listitem2 - listitem3 - listitem4 (without the separator here)
Listitem5 - listitem6 - listitem6 - listitem8 (without separator here either)
Listitem9 - etc ...
Does anyone have an idea?
Thank you in advance. Sebastian
There doesn’t seem to be a pure CSS solution, but you can use a bit of JS to set or unset a class based on whether an item is the first in a line.
Here I’m setting the text color to transparent rather than the content to "" because changing the content affects width, which then jumps around as it wraps/resizes.
a.firstInLine::before {
color: transparent;
}
The Javascript goes through the nodes and checks whether it’s lower on the page than the previous node. If it is (by more than a small margin of error), it sets the class firstInLine:
function calcY() {
document.querySelectorAll("p a").forEach((n, i, nodes) => {
if(i > 0) {
const thisY = n.getClientRects()[0].y;
const prevY = nodes[i - 1].getClientRects()[0].y;
if(thisY - prevY > 4) {
n.classList.add("firstInLine");
}
else {
n.classList.remove("firstInLine");
}
}
});
}
window.addEventListener("resize", calcY);
calcY();
I should add that there are a couple of other CSS things to set. We don’t want it to wrap, and in order for getClientRects to work right, it can’t be a purely inline element, so:
a {
white-space: nowrap;
display: inline-block;
}
CodePen
I have the following media queries. The first one is for certain screens below a certain width. The second is specifically for the iPhone X. Is it possible to override the first media query when it is an iPhone X only? The following does not seem to work
#media (max-width: 449px) {
h1.question { padding: 20px 0px; }
}
#media only screen
and (device-width : 375px)
and (device-height : 812px)
and (-webkit-device-pixel-ratio : 3) {
h1.question { padding-top: 50px !important; }
}
I believe what you're looking for is -webkit-min-device-pixel-ratio.
The -webkit-device-pixel-ratio feature is specified as a value. It is a range feature, meaning that you can also use the prefixed -webkit-min-device-pixel-ratio and -webkit-max-device-pixel-ratio variants to query minimum and maximum values, respectively. (source)
As a test of this I set up the following fiddle, which will output -webkit-min-device-pixel-ratio (with credit to this). Also stack snippet below.
https://jsfiddle.net/3w5rq8pj/10/
I tested this on several devices with the following results:
Actual iPhone 7 Plus / Result 3
Macbook Pro with Retina Display / Result 3
Lenovo Thinkpad (ie) / Result 0
Emulated iPhone 6 Plus on BrowserStack via Macbook Pro with Retina / Result 3
Emulated iPhone 6 Plus on BrowserStack via Lenovo Thinkpad / Result 3
In all these cases the Browserstack emulators returned the proper results (which honestly suprised me).
I also re-ran all the tests but removed -min from the query in the javascript, and every single test case returned 0.
function guess() {
var ls, l=0, h=8192, c=parseInt((l+h)/2), i=20;
while (i > 0 && (c - l >1) && (h - c>1)) {
i--; // Shouldn't take more than 13 guesses, but in case of bugs!
if (window.matchMedia('(-webkit-min-device-pixel-ratio: ' + c + ')').matches) {
l=c; ls=0;
} else {
h=c; ls=1;
}
c = parseInt((h+l)/2);
}
c -= ls;
document.getElementById("result").innerHTML = "min pixel ratio: " + c;
}
guess();
<div id="result"></div>
A lot of the information about Retina devices comes from ~2013 but not much recently.
It seems like, for example in retina.js, it includes anything with a device pixel ratio of > 1.5 to be "retina", but don't all smartphones have well over 1.5 these days? My desktop computer does as well.
My question then, why not just always serve the highest possible resolution images you have access to instead of creating the half-sized versions for "non-retina" devices, which as far as I know don't really exist much and won't suffer much from being served a higher resolution image.
Thanks!!!
Using 2x images is a huge pain.
Who can know what is "best," but I'm currently working with images in a combo like this:
I use a parent element so that the image will fill it - and that parent/or it's ancestors will determine any limits. You can use the picture element. (usually, the src are supplied by a CMS or something {{image.small.url}} etc.
The official answer to your questions would be, that people don't serve the higher res file to everything - because the file is bigger and they want the site to load as fast as possible. / but if you double the images size (twice as big as it will ever be presented, and compress to ~40 or so) then use the parent element to size it - it's actually a smaller file size. There are very specific studies on this. I don't know how that works for painting and browser rendering, though.
MARKUP
<figure class='poster'>
<img src='' alt=''
data-small='http://placehold.it/600'
data-medium='http://placehold.it/1000'
data-large='http://placehold.it/2000'
/>
</figure>
STYLES (stylus)
figure // just imagine the brackets if you want
margin: 0
img
display: block
width: 100%
height: auto
.poster
max-width: 400px
SCRIPT
$(document).on('ready', function() {
// $global
var $window = $(window);
var windowWidth;
var windowHeight;
function getWindowDimentions() {
windowWidth = $window.width();
windowHeight = $window.height();
}
function setResponsibleImageSrc(imageAncestorElement, container) {
var large = false; // innocent until proven guilty
var medium = false; // "
var context;
if ( !container ) {
context = windowWidth;
} else {
context = $(container).outerWidth();
}
var large = context > 900;
var medium = context > 550;
$(imageAncestorElement).each( function() {
var $this = $(this).find('img');
var src = {};
src.small = $this.data('small');
src.medium = $this.data('medium');
src.large = $this.data('large');
if ( large ) {
$this.attr('src', src.large);
} else if ( medium ) {
$this.attr('src', src.medium);
} else {
$this.attr('src', src.small);
}
});
};
$window.on('resize', function() { // this should jog a bit
getWindowDimentions();
setResponsibleImageSrc('.poster', 'body');
}).trigger('resize');
});
It all depends on what you are doing - and there is no silver bullet yet. The context for each image is so unique. My goal is to get in the ballpark for each size - keep the images compressed to 40 in Photoshop on export... double the size they should be, and then the parent squishes them for retina. The size is actually smaller in most cases.
CodePen example: http://codepen.io/sheriffderek/pen/bqpPra
I've a rather complicated website design I'm working on. I have the following 4 containers (I call them that, but they don't have the .container class)
In a wide screen layout:
In a narrow screen layout:
The issue I'm having is matching the total height of the white, grey and yellow containers with the blue container on a wide screen layout:
The grey and yellow containers are in a .row div, so adding the style { display: inline-flex } makes them the same height on a narrow screen layout:
However, this moves them completely to the side in the wide screen layout and this wouldn't match the combined white, grey and yellow containers with the blue container:
I tried a JavaScript solution as #Paulie_D recommended.
$(window).load(function () {
NormalizeHeights();
});
window.onresize = function (event) {
NormalizeHeights();
}
function NormalizeHeights() {
if (window.innerWidth >= 768) {
var carousel = $(".carousel-container");
var dashTop = $(".dash-row-top");
var panelLeft = $(".dash-row-bottom .panel-lightgray");
var panelRight = $(".dash-row-bottom .panel-yellow");
var carouselHeight = parseFloat(carousel.css('height'));
var dashTopHeight = parseFloat(dashTop.css('height'));
var panelLeftHeight = parseFloat(panelLeft.css('height'));
var panelRightHeight = parseFloat(panelRight.css('height'));
var dashBottomHeight;
if (panelLeftHeight > panelRightHeight) {
dashBottomHeight = panelLeftHeight;
}
else {
dashBottomHeight = panelRightHeight;
}
if (carouselHeight > (dashTopHeight + dashBottomHeight)) {
var difference = carouselHeight - (dashTopHeight + dashBottomHeight);
panelLeft.css("height", (dashBottomHeight + difference));
panelRight.css("height", (dashBottomHeight + difference));
}
else {
var difference = (dashTopHeight + dashBottomHeight) - carouselHeight;
carousel.css("height", (carouselHeight + difference));
panelLeft.css("height", (dashBottomHeight));
panelRight.css("height", (dashBottomHeight));
}
}
}
This works, sort off, but it's extremely unlikable in my estimation.
I had a similar problem and the solution I found was rather ugly but worked for me.
I used divs that would clear formats BUT would their presence would be conditioned (using ng-if). Programmatically, I measured the width of the screen and set a threshold. If the width was above the threshold, I set the location of the divs, measured the height of the contents and, when applicable, forcefully changed the height of all the relevant divs to look the same (note that you would need to set this size update AFTER A TIMER is fired to let the rendering to complete).
Hope this gives you some ideas and remember: I was the first to call this ugly.
I am trying to code my own responsive grid system using SASS. Using this simple Tutorial I was able to make a simple grid.
Currently, I am calculating the widths of all the columns according to their media query using this code:
#media #{$breakpoint-medium} {
.wrapper {
width: 95%;
max-width: $grid-max-width;
}
#for $i from 1 through $grid-columns {
.col-#{$i} {
width: 100% / $grid-columns * $i;
}
}
}
Where $grid-columns = 12
This works well, however, I'd like to center a block of text that I have designated as 8-columns wide, so I need to push, or offset this column by 2 columns.
I'm new to SASS so I'm still getting my bearings with using math in my CSS and such, but how can I adapt this code so that I can make a similar class, "push-#" that will automatically know to push the content properly?
Thanks so much in advance!
It is essentially the same math, you are just applying margin instead of width.
#for $i from 1 through $grid-columns {
.push-#{$i} {
margin-left: 100% / $grid-columns * $i;
}
}