Contain Text Within Irregular Shape
You can use css perspective here. Just apply it to the parent, then apply the reverse effect to the child. This way older browsers will simply display a square background, + responsive won't be an issue!
.container { font-family: Monospace; border: 3px solid black; text-align: center; padding: 0 20px; transform: perspective(10px) rotateX(-0.3deg); border-radius: 8px; max-width: 600px;}
.container div { transform: perspective(10px) rotateX(0.3deg);}
h2 { display: inline-block; padding: 0 10px; background-color: #fff; margin: -10px 0 0;}
<div class="container"> <div> <h2>What's the difference? Craft vs plant</h2> <p>I am trying to achieve the following in the most responsive, backward compatible way as possible. I appreciate that I may need to make a big compromise somewhere.</p> </div></div>
How can I wrap text around a non rectangular image?
You can use this method, where you float divs to block off the shape's area.
So - the answer is "Yes - it can be done". But as far as I know there's no "easy" way like a CSS "text-wrap" option.
How to find where to draw text inside an irregular shape represented by a UIBezierPath?
TextKit was built for tasks like this. You can create an array of paths outside of your bezier shape path and then set it as your textView's exclusionPaths:
textView.textContainer.exclusionPaths = [pathsAroundYourBezier];
Keep in mind that the exclusion paths are paths where text in the container will not be displayed. Apple documentation here: https://developer.apple.com/documentation/uikit/nstextcontainer/1444569-exclusionpaths
UPDATE DUE TO BUGS WITH EXCLUSION PATHS AT THE BEGINNING OF TEXTVIEW'S:
I've come up with a way to find where in a path text can fit.
Usage:
let pathVisible = rectPathSharpU(CGSize(width: 100, height: 125), origin: CGPoint(x: 0, y: 0))
let shapeLayer = CAShapeLayer()
shapeLayer.path = pathVisible.cgPath
shapeLayer.strokeColor = UIColor.green.cgColor
shapeLayer.backgroundColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 3
self.view.layer.addSublayer(shapeLayer)
let path = rectPathSharpU(CGSize(width: 100, height: 125), origin: CGPoint(x: 0, y: 0))
let fittingRect = findFirstRect(path: path, thatFits: "A".size())!
print("fittingRect: \(fittingRect)")
let label = UILabel.init(frame: fittingRect)
label.text = "A"
self.view.addSubview(label)
Output:
There may be cases with curved paths that will need to be taken into account, perhaps by iterating through every y point in a path bounds until a sizable space is found.
The function to find the first fitting rect:
func findFirstRect(path: UIBezierPath, thatFits: CGSize) -> CGRect? {
let points = path.cgPath.points
allPoints: for point in points {
var checkpoint = point
var size = CGSize(width: 0, height: 0)
thisPoint: while size.width <= path.bounds.width {
if path.contains(checkpoint) && path.contains(CGPoint.init(x: checkpoint.x + thatFits.width, y: checkpoint.y + thatFits.height)) {
return CGRect(x: checkpoint.x, y: checkpoint.y, width: thatFits.width, height: thatFits.height)
} else {
checkpoint.x += 1
size.width += 1
continue thisPoint
}
}
}
return nil
}
Extension for finding string size:
extension String {
func size(width:CGFloat = 220.0, font: UIFont = UIFont.systemFont(ofSize: 17.0, weight: .regular)) -> CGSize {
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = self
label.sizeToFit()
return CGSize(width: label.frame.width, height: label.frame.height)
}
}
Creating the test path:
func rectPathSharpU(_ size: CGSize, origin: CGPoint) -> UIBezierPath {
// Initialize the path.
let path = UIBezierPath()
// Specify the point that the path should start get drawn.
path.move(to: CGPoint(x: origin.x, y: origin.y))
// add lines to path
path.addLine(to: CGPoint(x: (size.width / 3) + origin.x, y: (size.height / 3 * 2) + origin.y))
path.addLine(to: CGPoint(x: (size.width / 3 * 2) + origin.x, y: (size.height / 3 * 2) + origin.y))
path.addLine(to: CGPoint(x: size.width + origin.x, y: origin.y))
path.addLine(to: CGPoint(x: (size.width) + origin.x, y: size.height + origin.y))
path.addLine(to: CGPoint(x: origin.x, y: size.height + origin.y))
// Close the path. This will create the last line automatically.
path.close()
return path
}
If this doesn't work for paths with a lot of arcs like your picture example, please post the actual path data so I can test with that.
Bonus: I also created a function to find the widest section of a symmetric path, though height isn't taken into account. Though it may be useful:
func findWidestY(path: UIBezierPath) -> CGRect {
var widestSection = CGRect(x: 0, y: 0, width: 0, height: 0)
let points = path.cgPath.points
allPoints: for point in points {
var checkpoint = point
var size = CGSize(width: 0, height: 0)
thisPoint: while size.width <= path.bounds.width {
if path.contains(checkpoint) {
checkpoint.x += 1
size.width += 1
continue thisPoint
} else {
if size.width > widestSection.width {
widestSection = CGRect(x: point.x, y: point.y, width: size.width, height: 1)
}
break thisPoint
}
}
}
return widestSection
}
In HTML5, can I make an irregular shaped text box?
If you're able to provide boxes which describe the shape, you might be able to use CSS3 Regions. Availability in your target browsers might be pretty poor though. This is probably the spec Šime mentioned.
SVG also claims support for this in an SVG 1.2 working draft. I'm not clear whether this has made it to a W3 Recommendation, or whether it's actually supported in browsers.
Update: the answers to this question suggest the SVG approach won't work right now.
Rendering CoreText within an irregular shape
I wrote a blog post about achieving text wrap with Core Text:
http://blog.amyworrall.com/post/11098565269/text-wrap-with-core-text
The feature is new in iOS 4.3 and MacOS X Lion. You can now firstly draw inside non-rectangular paths, and secondly pass in other paths to mask the flow (i.e. be the holes you wrap around).
Related Topics
Is It the Last 'Script' Element the Currently Running Script
Storing Arbitrary Info in HTML Tags for JavaScript
Trying to Set a Span Element Equal to a Variable Value in a Js Rock, Paper, Scissors Game
How to Add HTML Inside a Title Attribute
Phantomjs Page.Content Isn't Retrieving the Page Content
Good Beginners Tutorial to Socket.Io
How to Change the Playing Speed of Videos in HTML5
JavaScript Loading Screen While Page Loads
Disable Zoom on Input Focus in Android Webpage
How to Automatically Close Alerts Using Twitter Bootstrap
Invert Colors of an Image in CSS or JavaScript
Why Do People Minify CSS and JavaScript, When We Have Gzip
Why Are CSS Keyframe Animations Broken in Vue Components with Scoped Styling
How to List All CSS Variables Names/Values Pairs from Element
How to Make Div Slide from Right to Left
How to Avoid Animation Artifacts on My Touch-Draggable Border-Radius Element on iPad